nodemailer.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. 'use strict';
  2. const Mailer = require('./mailer');
  3. const shared = require('./shared');
  4. const SMTPPool = require('./smtp-pool');
  5. const SMTPTransport = require('./smtp-transport');
  6. const SendmailTransport = require('./sendmail-transport');
  7. const StreamTransport = require('./stream-transport');
  8. const JSONTransport = require('./json-transport');
  9. const SESTransport = require('./ses-transport');
  10. const fetch = require('./fetch');
  11. const packageData = require('../package.json');
  12. const ETHEREAL_API = 'https://api.nodemailer.com';
  13. const ETHEREAL_WEB = 'https://ethereal.email';
  14. let testAccount = false;
  15. module.exports.createTransport = function(transporter, defaults) {
  16. let urlConfig;
  17. let options;
  18. let mailer;
  19. if (
  20. // provided transporter is a configuration object, not transporter plugin
  21. (typeof transporter === 'object' && typeof transporter.send !== 'function') ||
  22. // provided transporter looks like a connection url
  23. (typeof transporter === 'string' && /^(smtps?|direct):/i.test(transporter))
  24. ) {
  25. if ((urlConfig = typeof transporter === 'string' ? transporter : transporter.url)) {
  26. // parse a configuration URL into configuration options
  27. options = shared.parseConnectionUrl(urlConfig);
  28. } else {
  29. options = transporter;
  30. }
  31. if (options.pool) {
  32. transporter = new SMTPPool(options);
  33. } else if (options.sendmail) {
  34. transporter = new SendmailTransport(options);
  35. } else if (options.streamTransport) {
  36. transporter = new StreamTransport(options);
  37. } else if (options.jsonTransport) {
  38. transporter = new JSONTransport(options);
  39. } else if (options.SES) {
  40. transporter = new SESTransport(options);
  41. } else {
  42. transporter = new SMTPTransport(options);
  43. }
  44. }
  45. mailer = new Mailer(transporter, options, defaults);
  46. return mailer;
  47. };
  48. module.exports.createTestAccount = function(apiUrl, callback) {
  49. let promise;
  50. if (!callback && typeof apiUrl === 'function') {
  51. callback = apiUrl;
  52. apiUrl = false;
  53. }
  54. if (!callback && typeof Promise === 'function') {
  55. promise = new Promise((resolve, reject) => {
  56. callback = shared.callbackPromise(resolve, reject);
  57. });
  58. }
  59. if (testAccount) {
  60. return callback(null, testAccount);
  61. }
  62. apiUrl = apiUrl || ETHEREAL_API;
  63. let chunks = [];
  64. let chunklen = 0;
  65. let req = fetch(apiUrl + '/user', {
  66. contentType: 'application/json',
  67. method: 'POST',
  68. body: Buffer.from(
  69. JSON.stringify({
  70. requestor: packageData.name,
  71. version: packageData.version
  72. })
  73. )
  74. });
  75. req.on('readable', () => {
  76. let chunk;
  77. while ((chunk = req.read()) !== null) {
  78. chunks.push(chunk);
  79. chunklen += chunk.length;
  80. }
  81. });
  82. req.once('error', err => callback(err));
  83. req.once('end', () => {
  84. let res = Buffer.concat(chunks, chunklen);
  85. let data;
  86. let err;
  87. try {
  88. data = JSON.parse(res.toString());
  89. } catch (E) {
  90. err = E;
  91. }
  92. if (err) {
  93. return callback(err);
  94. }
  95. if (data.status !== 'success' || data.error) {
  96. return callback(new Error(data.error || 'Request failed'));
  97. }
  98. delete data.status;
  99. testAccount = data;
  100. callback(null, testAccount);
  101. });
  102. return promise;
  103. };
  104. module.exports.getTestMessageUrl = function(info) {
  105. if (!info || !info.response) {
  106. return false;
  107. }
  108. let infoProps = new Map();
  109. info.response.replace(/\[([^\]]+)\]$/, (m, props) => {
  110. props.replace(/\b([A-Z0-9]+)=([^\s]+)/g, (m, key, value) => {
  111. infoProps.set(key, value);
  112. });
  113. });
  114. if (infoProps.has('STATUS') && infoProps.has('MSGID')) {
  115. return (testAccount.web || ETHEREAL_WEB) + '/message/' + infoProps.get('MSGID');
  116. }
  117. return false;
  118. };