There are 3 stages a plugin can hook to:
‘compile’ and ‘stream’ plugins can be attached with use(plugin)
method
transporter.use(step, pluginFunc)
Where
All plugins (including transports) get two arguments, the mail object and a callback function.
Mail object that is passed to the plugin function as the first argument is an object with the following properties:
If your plugin needs to get the full value of a param, for example the String value for the html content, you can use resolveContent() to convert Nodemailer compatible content objects to Strings or Buffers.
mail.resolveContent(obj, key, callback)
Where
function plugin(mail, callback) {
// if mail.data.html is a file or an url, it is returned as a Buffer
mail.resolveContent(mail.data, 'html', (err, html) => {
if(err){
return callback(err);
}
console.log('HTML contents: %s', html.toString());
callback();
});
};
Compile step plugins get only the mail.data object but not mail.message. If you need to access the latter as well, use ‘stream’ step instead.
This is really straightforward, your plugin can modify the mail.data object at will and once everything is finished run the callback function. If the callback gets an error object as an argument, then the process is terminated and the error is returned to the sendMail() callback.
The following plugin checks if text value is set and if not converts html value by removing all html tags.
transporter.use('compile', (mail, callback) => {
if(!mail.data.text && mail.data.html){
mail.data.text = mail.data.html.replace(/<[^>]*>/g, ' ');
}
callback();
});
Streaming step is invoked once the message structure is built and ready to be streamed to the transport. Plugin function does get mail.data as an argument but it is included just for the reference, modifying it should not change anything (unless the transport requires something from the mail.data, for example mail.data.envelope).
You can modify the mail.message object as you like, the message is not yet streaming anything (message starts streaming when the transport calls mail.message.createReadStream()).
In most cases you might be interested in the message.transform() method for applying transform streams to the raw message.
The following plugin replaces all tabs with spaces in the raw message.
let transformer = new (require('stream').Transform)();
transformer._transform = (chunk, encoding, done) => {
// replace all tabs with spaces in the stream chunk
for(let i = 0; i < chunk.length; i++){
if(chunk[i] === 0x09){
chunk[i] = 0x20;
}
}
this.push(chunk);
done();
};
transporter.use('stream', (mail, callback) => {
// apply output transformer to the raw message stream
mail.message.transform(transformer);
callback();
});
Additionally you might be interested in the message.getAddresses() method that returns the contents for all address fields as structured objects.
The following plugin prints address information to console.
transporter.use('stream', function(mail, callback) => {
let addresses = mail.message.getAddresses();
console.log('From: %s', JSON.stringify(addresses.from));
console.log('To: %s', JSON.stringify(addresses.to));
console.log('Cc: %s', JSON.stringify(addresses.cc));
console.log('Bcc: %s', JSON.stringify(addresses.bcc));
callback();
});
If you want to modify the created stream, you can add transform streams that the output will be piped through.
mail.message.transform(transformStream)
Where
Returns an address container object. Includes all parsed addresses from From, Sender, To, Cc, Bcc and Reply-To fields. All returned values are arrays, including from
.
Possible return values (all arrays in the form of [{name:'', address:''}]
):
If no addresses were found for a particular field, the field is not set in the response object.
Transports are objects that have a method send() and properies name and version. A transport object is passed to the nodemailer.createTransport(transport)
method to create the transporter object.
This is the name of the transport object. For example ‘SMTP’ or ‘SES’ etc.
transport.name = require('package.json').name;
This should be the transport module version. For example ‘0.1.0’.
transport.version = require('package.json').version;
This is the method that actually sends out emails. The method is basically the same as ‘stream’ plugin functions. It gets two arguments: mail and a callback. To start streaming the message, create the stream with mail.message.createReadStream()
Callback function should return an info object as the second argument. This info object should contain and envelope object with envelope data and a messageId value with the Message-Id header (including the surrounding < & > brackets),
The following example pipes the raw stream from Nodemailer to the console.
transport.send = (mail, callback) => {
let input = mail.message.createReadStream();
let envelope = mail.message.getEnvelope();
let messageId = mail.message.messageId();
input.pipe(process.stdout);
input.on('end', function() {
callback(null, {
envelope,
messageId
});
});
};
If your transport needs to be closed explicitly, you can implement a close() method.
This is purely optional feature and only makes sense in special contexts (eg. closing a SMTP pool).
transport.close = () => {
transport.pool = null;
};
If your transport is able to notify about idling state by issuing ‘idle’ events then this method should return if the transport is still idling or not.
transport.idling = true;
transport.isIdle = () => transport.idling;
transport.send = (mail, callback) => {
transport.idling = false;
sendMail(mail, ()=>{
transport.idling = true;
transport.emit('idle');
});
};
This example creates and uses a transport object that pipes the raw message to console
let transport = {
name: 'minimal',
version: '0.1.0',
send: (mail, callback) => {
let input = mail.message.createReadStream();
input.pipe(process.stdout);
input.on('end', function () {
callback(null, true);
});
}
};
let transporter = nodemailer.createTransport(transport);
transporter.sendMail({
from: 'sender',
to: 'receiver',
subject: 'hello',
text: 'hello world!'
});
Once you have a transport object, you can create a mail transporter out of it.
let transport = require('some-transport-method');
let transporter = nodemailer.createTransport(transport);
transporter.sendMail({
from: '...',
to: '...',
message
});