Create Email.sendAsync method without using Fibers.

This commit is contained in:
Edimar Cardoso
2022-07-27 15:04:55 -03:00
parent 815bcd980e
commit 631b74ff50
2 changed files with 98 additions and 15 deletions

View File

@@ -140,6 +140,10 @@ const getTransport = function () {
let nextDevModeMailId = 0;
let output_stream = process.stdout;
EmailTest._getAndIncNextDevModeMailId = function () {
return nextDevModeMailId++;
};
// Testing hooks
EmailTest.overrideOutputStream = function (stream) {
nextDevModeMailId = 0;
@@ -150,11 +154,9 @@ EmailTest.restoreOutputStream = function () {
output_stream = process.stdout;
};
const devModeSend = async function (mail) {
const devModeSendAsync = async function (mail, stream) {
return new Promise((resolve, reject) => {
let devModeMailId = nextDevModeMailId++;
const stream = output_stream;
let devModeMailId = EmailTest._getAndIncNextDevModeMailId();
// This approach does not prevent other writers to stdout from interleaving.
stream.write('====== BEGIN MAIL #' + devModeMailId + ' ======\n');
@@ -166,7 +168,7 @@ const devModeSend = async function (mail) {
readStream.pipe(stream, { end: false });
readStream.on('end', function () {
stream.write('====== END MAIL #' + devModeMailId + ' ======\n');
resolve();
resolve(stream);
});
readStream.on('error', (err) => reject(err));
});
@@ -235,6 +237,7 @@ Email.customTransport = undefined;
* `new EmailInternals.NpmModules.mailcomposer.module`.
*/
Email.sendAsync = async function (options) {
const stream = output_stream;
return new Promise((resolve, reject) => {
if (options.mailComposer) {
options = options.mailComposer.mail;
@@ -277,12 +280,34 @@ Email.sendAsync = async function (options) {
resolve();
return;
}
devModeSend(options)
.then(() => resolve())
devModeSendAsync(options, stream)
.then((currentStream) => resolve(currentStream))
.catch((err) => reject(err));
});
};
// TODO To remove in future versions (3.0.0 ????)
const devModeSend = function (mail) {
let devModeMailId = EmailTest._getAndIncNextDevModeMailId();
const stream = output_stream;
// This approach does not prevent other writers to stdout from interleaving.
stream.write('====== BEGIN MAIL #' + devModeMailId + ' ======\n');
stream.write(
'(Mail not sent; to enable sending, set the MAIL_URL ' +
'environment variable.)\n'
);
const readStream = new MailComposer(mail).compile().createReadStream();
readStream.pipe(stream, { end: false });
const future = new Future();
readStream.on('end', function () {
stream.write('====== END MAIL #' + devModeMailId + ' ======\n');
future.return();
});
future.wait();
};
/**
* @summary Send an email. Throws an `Error` on failure to contact mail server
* or if mail server returns an error. All fields should match
@@ -316,12 +341,32 @@ Email.sendAsync = async function (options) {
* You can create a `MailComposer` object via
* `new EmailInternals.NpmModules.mailcomposer.module`.
*/
Email.send = async function (options) {
const future = new Future();
Email.sendAsync(options)
.then(() => future.return())
.catch((err) => {
throw err;
});
future.wait();
Email.send = function (options) {
if (options.mailComposer) {
options = options.mailComposer.mail;
}
let send = true;
sendHooks.forEach((hook) => {
send = hook(options);
return send;
});
if (!send) return;
const customTransport = Email.customTransport;
if (customTransport) {
const packageSettings = Meteor.settings.packages?.email || {};
customTransport({ packageSettings, ...options });
return;
}
if (
Meteor.isProduction ||
process.env.MAIL_URL ||
Meteor.settings.packages?.email
) {
const transport = getTransport();
smtpSend(transport, options);
return;
}
devModeSend(options);
};

View File

@@ -25,6 +25,44 @@ function canonicalize(string) {
.replace(/(boundary="|^--)--[^\s"]+?(-Part|")/mg, "$1--...$2");
}
Tinytest.addAsync('[Async] email - fully customizable', function (test, onComplete) {
smokeEmailTest(function () {
Email.sendAsync({
from: 'foo@example.com',
to: 'bar@example.com',
cc: ['friends@example.com', 'enemies@example.com'],
subject: 'This is the subject',
text: 'This is the body\nof the message\nFrom us.',
headers: {
'X-Meteor-Test': 'a custom header',
Date: 'dummy',
},
}).then((currentStream) => {
test.equal(
canonicalize(currentStream.getContentsAsString('utf8')),
'====== BEGIN MAIL #0 ======\n' +
devWarningBanner +
'Content-Type: text/plain; charset=utf-8\r\n' +
'X-Meteor-Test: a custom header\r\n' +
'Date: dummy\r\n' +
'From: foo@example.com\r\n' +
'To: bar@example.com\r\n' +
'Cc: friends@example.com, enemies@example.com\r\n' +
'Subject: This is the subject\r\n' +
'Message-ID: <...>\r\n' +
'Content-Transfer-Encoding: 7bit\r\n' +
'MIME-Version: 1.0\r\n' +
'\r\n' +
'This is the body\n' +
'of the message\n' +
'From us.\r\n' +
'====== END MAIL #0 ======\n'
);
onComplete();
});
});
});
Tinytest.add("email - fully customizable", function (test) {
smokeEmailTest(function(stream) {
Email.send({