mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Create Email.sendAsync method without using Fibers.
This commit is contained in:
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user