%PDF- %PDF-
Direktori : /home/opti/workflow/node_modules/express-mailer/node_modules/nodemailer/lib/ |
Current File : /home/opti/workflow/node_modules/express-mailer/node_modules/nodemailer/lib/nodemailer.js |
"use strict"; var transportHandler = require("./transport"), Transport = transportHandler.Transport, MailComposer = require("mailcomposer").MailComposer, XOAuthGenerator = require("./xoauth").XOAuthGenerator, helpers = require("./helpers"), crypto = require("crypto"), os = require("os"), net = require("net"), packageData = require("../package.json"), publicAddress = require("public-address"); /* * Version constants */ var X_MAILER_NAME = "Nodemailer", X_MAILER_HOMEPAGE = packageData.homepage; 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); }; // exports mail generator Object.defineProperty(module.exports, "mail", { get: function(){ var transport = module.exports.createTransport("direct"); return function(mailData){ transport.sendMail(mailData); }; } }); // 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.identityString){ mailcomposerOptions.identityString = this.options.identityString; } 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); } if(this.transport){ details.push((this.transport.transportType || "").toLowerCase() + (this.transport.version ? "/" + this.transport.version : "")); } 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){ var self = this; process.nextTick(function(){ if(!self.transport || !self.transport.transport){ return callback(new Error("No transport method defined")); } // transport.options.resolveHostname is set to true, resolve pulbic // hostname for the machine and use self when generating Message-ID values // or when communicating with SMTP if(self.transport.options && self.transport.options.resolveHostname && !self.transport.options.name){ return publicHostnameResolver.resolve((function(err, resolved){ self.transport.options.name = self.resolveHostname( resolved ? resolved.hostname : self.options.name); callback(); }).bind(self)); } 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(); // setup dsn if(this.options.dsn){ this.mailcomposer.options.dsn = this.options.dsn; } }; /** * <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], true); } } }; /** * <p>Add some required headers to the message, such as Date: and Message-Id:</p> */ Nodemailer.prototype.setModuleHeaders = function(){ var messageId, transportOptions = this.transport && this.transport.options && typeof this.transport.options == "object" && this.transport.options || {}; // Mailer name + version // if xMailer is explicitly set to false, skip the X-Mailer header if(transportOptions.xMailer !== false){ this.mailcomposer.addHeader("X-Mailer", transportOptions.xMailer || 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 = crypto.randomBytes(15).toString("hex") +"@"+ this.resolveHostname(this.options.name || transportOptions.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); } }; /** * Resolves hostname, prefers given argument. If resolved * name is an IP address, "localhost" is used * * @param {String} [name] Preferred hostname * @return {String} Resolved hostname */ Nodemailer.prototype.resolveHostname = function(name){ if(name === true){ name = false; } if(!name || net.isIP(name.replace(/[\[\]]/g, "").trim())){ name = (os.hostname && os.hostname()) || ""; } if(!name || net.isIP(name.replace(/[\[\]]/g, "").trim())){ name = "localhost"; } return name.toLowerCase(); }; /** * Interface for resolving public hostname for the current machine * Resolves the hostname only once and uses the cached value later on */ var publicHostnameResolver = { _callbacks: [], _resolving: false, _resolved: false, /** * Resolve hostname for the current machine * * @param {Function} callback Function with an error object and resolved data as arguments */ resolve: function(callback){ if(this._resolved){ return callback(null, this._resolved); } this._callbacks.push(callback); if(!this._resolving){ this._startResolving(); } }, /** * Initiate hostname resolving */ _startResolving: function(){ this._resolving = true; publicAddress((function(err, data){ this._resolving = false; // if the resolving failed, skip it this._resolved = data || {}; // emit all queued callbacks this._callbacks.forEach((function(callback){ callback(null, this._resolved); }).bind(this)); }).bind(this)); } };