UNPKG

nodemailer

Version:

Easy to use module to send e-mails, supports unicode and SSL/TLS

333 lines (274 loc) 9.8 kB
var Transport = require("./transport").Transport, MailComposer = require("mailcomposer").MailComposer, XOAuthGenerator = require("./xoauth").XOAuthGenerator, helpers = require("./helpers"), packageData; try{ packageData = require("../package.json"); }catch(E){ // probably node 0.4 which doesn't support loading json files as objects packageData = JSON.parse( require("fs"). readFileSync( require("path"). join( __dirname, "..", "package.json" ) ) ); } /* * Version constants */ var X_MAILER_NAME = "Nodemailer", X_MAILER_HOMEPAGE = "http://www.nodemailer.com/"; module.exports.X_MAILER_NAME = X_MAILER_NAME; module.exports.X_MAILER_HOMEPAGE = X_MAILER_HOMEPAGE; // Export createTransport method module.exports.createTransport = function(type, options){ var transport = new Transport(type, options); transport.sendMail = function(options, callback){ options = options || {}; options.transport = options.transport || transport; sendMail(options, callback); }; return transport; }; //Export createXOAuthGenerator function module.exports.createXOAuthGenerator = function(options){ return new XOAuthGenerator(options); }; // Export Transport constructor module.exports.Transport = Transport; // Export Nodemailer constructor module.exports.Nodemailer = Nodemailer; // Export sendMail function (and the alias send_mail for legacy) module.exports.sendMail = module.exports.send_mail = sendMail; function sendMail(options, callback){ var mailer = new Nodemailer(options); mailer.validateSettings(function(err){ if(err){ // report validation error back to the client return callback(err); }else{ // try to send the e-mail message mailer.sendMail(callback); } }); return mailer; } /** * <p>Generates a Nodemailer object which is the main 'hub' for managing the * send process</p> * * @constructor * @param {Object} options Message options object, see README for the complete list of possible options */ function Nodemailer(options){ var mailcomposerOptions = {}; this.options = options || {}; this.transport = this.options.transport; mailcomposerOptions.identityString = X_MAILER_NAME + " " + packageData.version; if(this.options.encoding){ mailcomposerOptions.encoding = this.options.encoding; } if(this.options.charset){ mailcomposerOptions.charset = this.options.charset; } if(!!this.options.forceEmbeddedImages){ mailcomposerOptions.forceEmbeddedImages = true; } this.mailcomposer = new MailComposer(mailcomposerOptions); if(!this.transport){ this.transport = this.getGlobalTransport(); } } /** * <p>Generates an user agent string for Nodemailer with homepage, version etc.</p> * * @return {String} user agent string for X-Mailer value */ Nodemailer.prototype.generateUserAgentString = function(){ var details = []; if(packageData.version){ details.push(packageData.version); } if(X_MAILER_HOMEPAGE){ details.push("+"+X_MAILER_HOMEPAGE); } return X_MAILER_NAME+ (details.length?" ("+details.join("; ")+")":""); }; /** * <p>Add support for legacy transport settings by checking for global * variables SMTP, sendmail and SES</p> * * @return {Object} {@link Transport} object */ Nodemailer.prototype.getGlobalTransport = function(){ if(this.options.SMTP){ // cache the transport for SMTP as it is actually a connection pool if(!this.options.SMTP._smtp_transport){ this.options.SMTP._smtp_transport = new Transport("SMTP", this.options.SMTP); } return this.options.SMTP._smtp_transport; }else if(this.options.sendmail){ return new Transport("sendmail", this.options.sendmail); }else if(this.options.SES){ return new Transport("SES", this.options.SES); }else if(module.exports.SMTP){ // cache the transport for SMTP as it is actually a connection pool if(!module.exports._smtp_transport){ module.exports._smtp_transport = new Transport("SMTP", module.exports.SMTP); } return module.exports._smtp_transport; }else if(module.exports.sendmail){ return new Transport("sendmail", module.exports.sendmail); }else if(module.exports.SES){ return new Transport("SES", module.exports.SES); } return false; }; /** * <p>Doesn't do much currently, if the future should link to transport * validation methods. For example in case of SES should check that AWS * keys are set up etc.</p> * * @param {Function} callback Callback function to run after validation */ Nodemailer.prototype.validateSettings = function(callback){ if(!this.transport || !this.transport.transport){ return callback(new Error("No transport method defined")); } callback(null); }; /** * <p>Send the e-mail message by using data from the original options object * and selected transport</p> * * @param {Function} callback Callback function to run when the e-mail has been sent (or it failed) */ Nodemailer.prototype.sendMail = function(callback){ // compose the e-mail this.generateMailObject(); // send the message using preselected transport method this.transport.sendMailWithTransport(this.mailcomposer, callback); }; /** * <p>Uses the data from the original options object to compose a mailcomposer * e-mail message that can be later streamed to the selected transport</p> */ Nodemailer.prototype.generateMailObject = function(){ // set envelope data, subject etc. this.setGeneralOptions(); // set module defined headers (date, message-id, etc.) this.setModuleHeaders(); // set user defined headers (if any) this.setUserHeaders(); // set alternatives (if any) this.setAlternatives(); // set attachments (if any) this.setAttachments(); }; /** * <p>Uses the general options (message sender and receiver, subject body, etc.) * to set mailcomposer properties. Includes support for legacy properties.</p> */ Nodemailer.prototype.setGeneralOptions = function(){ // generate plaintext if only HTML exists and generateTextFromHTML is true if(!(this.options.text || this.options.body) && (this.options.html) && this.options.generateTextFromHTML){ this.options.text = helpers.stripHTML(this.options.html); } var acceptedFields = ["from", "sender", "to", "subject", "replyTo", "debug", "reply_to", "cc", "bcc", "body", "text", "html", "envelope", "inReplyTo", "references"], mailOptions = {}, keys = Object.keys(this.options), key; for(var i=0, len=keys.length; i<len; i++){ key = keys[i]; if(acceptedFields.indexOf(key) >=0 && this.options[key]){ mailOptions[key] = this.options[key]; } } if(this.options.debug){ console.log(mailOptions); } this.mailcomposer.setMessageOption(mailOptions); }; /** * <p>If the 'headers' property was set on the options, add the values to the * header of the e-mail message</p> */ Nodemailer.prototype.setUserHeaders = function(){ if(typeof this.options.headers != "object"){ return; } var keys = Object.keys(this.options.headers), key; for(var i=0, len=keys.length; i<len; i++){ key = keys[i]; if(this.options.headers[key]){ this.mailcomposer.addHeader(key, this.options.headers[key]); } } }; /** * <p>Add some required headers to the message, such as Date: and Message-Id:</p> */ Nodemailer.prototype.setModuleHeaders = function(){ var messageId; // Mailer name + version this.mailcomposer.addHeader("X-Mailer", this.generateUserAgentString()); // Date if(this.options.date){ this.mailcomposer.addHeader("Date", this.options.date); }else{ this.mailcomposer.addHeader("Date", new Date().toUTCString()); } // Message ID if(this.options.messageId){ messageId = this.options.messageId; }else if(this.options.messageId !== false){ messageId = Date.now()+Math.random().toString(16).substr(1) +"@"+ X_MAILER_NAME; } if(messageId){ this.mailcomposer.addHeader("Message-Id", "<"+messageId+">"); this.mailcomposer._messageId = messageId; } }; /** * <p>If attachment array is set on the options object, add these alternatives * to the mailcomposer object</p> */ Nodemailer.prototype.setAlternatives = function(){ var alternative; if(!this.options.alternatives){ return; } // convert non array value to an array if needed this.options.alternatives = [].concat(this.options.alternatives); for(var i=0, len=this.options.alternatives.length; i<len; i++){ alternative = this.options.alternatives[i]; this.mailcomposer.addAlternative(alternative); } }; /** * <p>If attachment array is set on the options object, add these attachments * to the mailcomposer object</p> */ Nodemailer.prototype.setAttachments = function(){ var attachment; if(!this.options.attachments){ return; } // convert non array value to an array if needed this.options.attachments = [].concat(this.options.attachments); for(var i=0, len=this.options.attachments.length; i<len; i++){ attachment = this.options.attachments[i]; attachment.userAgent = attachment.userAgent || this.generateUserAgentString(); this.mailcomposer.addAttachment(attachment); } };