123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- 'use strict';
- const spawn = require('child_process').spawn;
- const packageData = require('../../package.json');
- const LeWindows = require('./le-windows');
- const LeUnix = require('./le-unix');
- const shared = require('../shared');
- /**
- * Generates a Transport object for Sendmail
- *
- * Possible options can be the following:
- *
- * * **path** optional path to sendmail binary
- * * **newline** either 'windows' or 'unix'
- * * **args** an array of arguments for the sendmail binary
- *
- * @constructor
- * @param {Object} optional config parameter for Sendmail
- */
- class SendmailTransport {
- constructor(options) {
- options = options || {};
- // use a reference to spawn for mocking purposes
- this._spawn = spawn;
- this.options = options || {};
- this.name = 'Sendmail';
- this.version = packageData.version;
- this.path = 'sendmail';
- this.args = false;
- this.winbreak = false;
- this.logger = shared.getLogger(this.options, {
- component: this.options.component || 'sendmail'
- });
- if (options) {
- if (typeof options === 'string') {
- this.path = options;
- } else if (typeof options === 'object') {
- if (options.path) {
- this.path = options.path;
- }
- if (Array.isArray(options.args)) {
- this.args = options.args;
- }
- this.winbreak = ['win', 'windows', 'dos', '\r\n'].includes((options.newline || '').toString().toLowerCase());
- }
- }
- }
- /**
- * <p>Compiles a mailcomposer message and forwards it to handler that sends it.</p>
- *
- * @param {Object} emailMessage MailComposer object
- * @param {Function} callback Callback function to run when the sending is completed
- */
- send(mail, done) {
- // Sendmail strips this header line by itself
- mail.message.keepBcc = true;
- let envelope = mail.data.envelope || mail.message.getEnvelope();
- let messageId = mail.message.messageId();
- let args;
- let sendmail;
- let returned;
- let transform;
- if (this.args) {
- // force -i to keep single dots
- args = ['-i'].concat(this.args).concat(envelope.to);
- } else {
- args = ['-i'].concat(envelope.from ? ['-f', envelope.from] : []).concat(envelope.to);
- }
- let callback = err => {
- if (returned) {
- // ignore any additional responses, already done
- return;
- }
- returned = true;
- if (typeof done === 'function') {
- if (err) {
- return done(err);
- } else {
- return done(null, {
- envelope: mail.data.envelope || mail.message.getEnvelope(),
- messageId,
- response: 'Messages queued for delivery'
- });
- }
- }
- };
- try {
- sendmail = this._spawn(this.path, args);
- } catch (E) {
- this.logger.error(
- {
- err: E,
- tnx: 'spawn',
- messageId
- },
- 'Error occurred while spawning sendmail. %s',
- E.message
- );
- return callback(E);
- }
- if (sendmail) {
- sendmail.on('error', err => {
- this.logger.error(
- {
- err,
- tnx: 'spawn',
- messageId
- },
- 'Error occurred when sending message %s. %s',
- messageId,
- err.message
- );
- callback(err);
- });
- sendmail.once('exit', code => {
- if (!code) {
- return callback();
- }
- let err;
- if (code === 127) {
- err = new Error('Sendmail command not found, process exited with code ' + code);
- } else {
- err = new Error('Sendmail exited with code ' + code);
- }
- this.logger.error(
- {
- err,
- tnx: 'stdin',
- messageId
- },
- 'Error sending message %s to sendmail. %s',
- messageId,
- err.message
- );
- callback(err);
- });
- sendmail.once('close', callback);
- sendmail.stdin.on('error', err => {
- this.logger.error(
- {
- err,
- tnx: 'stdin',
- messageId
- },
- 'Error occurred when piping message %s to sendmail. %s',
- messageId,
- err.message
- );
- callback(err);
- });
- let recipients = [].concat(envelope.to || []);
- if (recipients.length > 3) {
- recipients.push('...and ' + recipients.splice(2).length + ' more');
- }
- this.logger.info(
- {
- tnx: 'send',
- messageId
- },
- 'Sending message %s to <%s>',
- messageId,
- recipients.join(', ')
- );
- transform = this.winbreak ? new LeWindows() : new LeUnix();
- let sourceStream = mail.message.createReadStream();
- transform.once('error', err => {
- this.logger.error(
- {
- err,
- tnx: 'stdin',
- messageId
- },
- 'Error occurred when generating message %s. %s',
- messageId,
- err.message
- );
- sendmail.kill('SIGINT'); // do not deliver the message
- callback(err);
- });
- sourceStream.once('error', err => transform.emit('error', err));
- sourceStream.pipe(transform).pipe(sendmail.stdin);
- } else {
- return callback(new Error('sendmail was not found'));
- }
- }
- }
- module.exports = SendmailTransport;
|