1 var Transport = require("./transport").Transport, 2 createTransport = require("./transport").createTransport, 3 MailComposer = require("mailcomposer").MailComposer, 4 helpers = require("./helpers"); 5 6 /* 7 * Version constants 8 */ 9 var X_MAILER_NAME = "Nodemailer", 10 X_MAILER_VERSION = "0.3.3; +http://www.nodemailer.org"; 11 12 13 // Export createTransport method 14 module.exports.createTransport = createTransport; 15 16 // Export Transport constructor 17 module.exports.Transport = Transport; 18 19 // Export Nodemailer constructor 20 module.exports.Nodemailer = Nodemailer; 21 22 // Export sendMail function (and the alias send_mail for legacy) 23 module.exports.sendMail = module.exports.send_mail = function(options, callback){ 24 var mailer = new Nodemailer(options); 25 26 mailer.validateSettings(function(err){ 27 if(err){ 28 // report validation error back to the client 29 return callback(err); 30 }else{ 31 // try to send the e-mail message 32 mailer.sendMail(callback); 33 } 34 }); 35 36 return mailer; 37 }; 38 39 40 /** 41 * <p>Generates a Nodemailer object which is the main 'hub' for managing the 42 * send process</p> 43 * 44 * @constructor 45 * @param {Object} options Message options object, see README for the complete list of possible options 46 */ 47 function Nodemailer(options){ 48 this.options = options || {}; 49 50 this.transport = this.options.transport; 51 52 this.mailcomposer = new MailComposer(); 53 54 if(!this.transport){ 55 this.transport = this.getGlobalTransport(); 56 } 57 } 58 59 /** 60 * <p>Add support for legacy transport settings by checking for global 61 * variables SMTP, sendmail and SES</p> 62 * 63 * @return {Object} {@link Transport} object 64 */ 65 Nodemailer.prototype.getGlobalTransport = function(){ 66 if(this.options.SMTP){ 67 // cache the transport for SMTP as it is actually a connection pool 68 if(!this.options.SMTP._smtp_transport){ 69 this.options.SMTP._smtp_transport = createTransport("SMTP", this.options.SMTP); 70 } 71 return this.options.SMTP._smtp_transport; 72 }else if(this.options.sendmail){ 73 return createTransport("sendmail", this.options.sendmail); 74 }else if(this.options.SES){ 75 return createTransport("SES", this.options.SES); 76 }else if(module.exports.SMTP){ 77 // cache the transport for SMTP as it is actually a connection pool 78 if(!module.exports._smtp_transport){ 79 module.exports._smtp_transport = createTransport("SMTP", module.exports.SMTP); 80 } 81 return module.exports._smtp_transport; 82 }else if(module.exports.sendmail){ 83 return createTransport("sendmail", module.exports.sendmail); 84 }else if(module.exports.SES){ 85 return createTransport("SES", module.exports.SES); 86 } 87 return false; 88 }; 89 90 /** 91 * <p>Doesn't do much currently, if the future should link to transport 92 * validation methods. For example in case of SES should check that AWS 93 * keys are set up etc.</p> 94 * 95 * @param {Function} callback Callback function to run after validation 96 */ 97 Nodemailer.prototype.validateSettings = function(callback){ 98 if(!this.transport || !this.transport.transport){ 99 return callback(new Error("No transport method defined")); 100 } 101 callback(null); 102 }; 103 104 /** 105 * <p>Send the e-mail message by using data from the original options object 106 * and selected transport</p> 107 * 108 * @param {Function} callback Callback function to run when the e-mail has been sent (or it failed) 109 */ 110 Nodemailer.prototype.sendMail = function(callback){ 111 // compose the e-mail 112 this.generateMailObject(); 113 // send the message using preselected transport method 114 this.transport.sendMail(this.mailcomposer, callback); 115 }; 116 117 /** 118 * <p>Uses the data from the original options object to compose a mailcomposer 119 * e-mail message that can be later streamed to the selected transport</p> 120 */ 121 Nodemailer.prototype.generateMailObject = function(){ 122 123 // set envelope data, subject etc. 124 this.setGeneralOptions(); 125 126 // set module defined headers (date, message-id, etc.) 127 this.setModuleHeaders(); 128 129 // set user defined headers (if any) 130 this.setUserHeaders(); 131 132 // set attachments (if any) 133 this.setAttachments(); 134 }; 135 136 /** 137 * <p>Uses the general options (message sender and receiver, subject body, etc.) 138 * to set mailcomposer properties. Includes support for legacy properties.</p> 139 */ 140 Nodemailer.prototype.setGeneralOptions = function(){ 141 142 // generate plaintext if only HTML exists and generateTextFromHTML is true 143 if(!(this.options.text || this.options.body) && (this.options.html) && 144 this.options.generateTextFromHTML){ 145 this.options.text = helpers.stripHTML(this.options.html); 146 } 147 148 var acceptedFields = ["from", "sender", "to", "subject", "replyTo", "debug", 149 "reply_to", "cc", "bcc", "body", "text", "html"], 150 mailOptions = {}, 151 keys = Object.keys(this.options), 152 key; 153 154 155 156 for(var i=0, len=keys.length; i<len; i++){ 157 key = keys[i]; 158 if(acceptedFields.indexOf(key) >=0 && this.options[key]){ 159 mailOptions[key] = this.options[key]; 160 } 161 } 162 163 if(this.options.debug){ 164 console.log(mailOptions); 165 } 166 167 this.mailcomposer.setMessageOption(mailOptions); 168 }; 169 170 /** 171 * <p>If the 'headers' property was set on the options, add the values to the 172 * header of the e-mail message</p> 173 */ 174 Nodemailer.prototype.setUserHeaders = function(){ 175 if(typeof this.options.headers != "object"){ 176 return; 177 } 178 var keys = Object.keys(this.options.headers), 179 key; 180 181 for(var i=0, len=keys.length; i<len; i++){ 182 key = keys[i]; 183 if(this.options.headers[key]){ 184 this.mailcomposer.addHeader(key, this.options.headers[key]); 185 } 186 } 187 }; 188 189 /** 190 * <p>Add some required headers to the message, such as Date: and Message-Id:</p> 191 */ 192 Nodemailer.prototype.setModuleHeaders = function(){ 193 194 // Mailer name + version 195 this.mailcomposer.addHeader("X-Mailer", X_MAILER_NAME+ 196 (X_MAILER_VERSION?" ("+X_MAILER_VERSION+")":"")); 197 198 // Date 199 this.mailcomposer.addHeader("Date", new Date().toUTCString()); 200 201 // Message ID 202 this.mailcomposer.addHeader("Message-Id", "<"+ 203 Date.now()+Math.random().toString(16).substr(1)+"@"+ 204 X_MAILER_NAME+">"); 205 }; 206 207 /** 208 * <p>If attachment array is set on the options object, add these attachments 209 * to the mailcomposer object</p> 210 */ 211 Nodemailer.prototype.setAttachments = function(){ 212 if(!Array.isArray(this.options.attachments)){ 213 return; 214 } 215 var attachment; 216 for(var i=0, len=this.options.attachments.length; i<len; i++){ 217 attachment = this.options.attachments[i]; 218 this.mailcomposer.addAttachment(attachment); 219 } 220 };