Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Compose responsive email templates easily, fill them with models, and send them out.
Compose responsive email templates easily, fill them with models, and send them out.
This is the stuff responsible for sending beautiful emails in Pony Foo. I've isolated that code, and turned it into a reusable package, called campaign
. It comes with a dead simple API, and a beautiful responsive layout, originally written by MailChimp, adapted by me. It's also easily configurable, and comes with nice conventions over configuration, so you don't need to do a lot to get going.
It uses Mustache to fill out templates, and Mandrill (by default) to send emails, although providing your own provider
, to send emails through something else, is pretty easy.
Quick links for reference.
Install using npm
.
npm i --save campaign
Set it up.
Construct a client
.
var client = require('campaign')();
(the default provider needs an API key for Mandrill, read on)
Send emails!
client.send(template, options, done);
client.sendString('<p>{{something}}</p>', options, done);
(detailed information below)
Here is a screenshot of an email sent using this library, as seen on Pony Foo subscriptions, in production. This email is using the default layout provided by campaign
.
Here are the default options, they are explained below.
{
"mandrill": {
"apiKey": "<not provided>",
"debug": false
},
"from": "<not provided>",
"provider": "<default>",
"trap": false,
"headerImage": "<not provided>",
"layout": "<defaults>"
}
trap
If true
, then emails won't be sent to any recipients at all. You could also set trap
to nico@bevacqua.io
, and all emails would be sent to me instead of the intended recipients. Great for spamming me, and also great for testing.
When you trap
recipients, the email will get a nifty JSON at the end detailing the actual recipients that would've gotten it.
mandrill
By default, the Mandrill service is used to send the emails. Mandrill is really awesome and you should be using it. It has a generous free plan.
At the time they host their API's source code in Bit Bucket, which is kind of weird, but you can read through it nonetheless.
You need to provide an API key in apiKey
, and that's all there is to it. You might prefer to ignore this configuration option, and merely set process.env.MANDRILL_APIKEY
. That works, too.
from
The from
address for our emails. The provider
is responsible for trying to make it look like that's the send address. Not necessarily used for authentication.
provider
You can use other email providers, creating your own or choosing one that comes with campaign
. To implement it yourself, you need to create a custom provider
object. The provider
object should have a send
function, which takes a model
, and a done
callback. You can read more about custom providers below.
headerImage
You may provide the full path to an image. This image will be encoded in base64
and embedded into the email as a heading. Embedding helps people view your emails offline.
This image should have a 3:1
ish ratio. For instance, I use 600x180
in my blog's emails.
layout
The layout used in your emails. Templates for email sending are meant to have the bare minimum needed to fill out an email. Since you want a consistent UX, the same layout
should be used for every email your product sends.
A default layout template
is provided. You can provide a different one, just set layout
to the absolute path of a Mustache template file. For information about the model passed to the layout, see the Templates section.
Once you've created a client, you can start sending emails. Here are the default options, and what you need to fill out.
{
"subject": "<not provided>",
"preview": "<options.subject>",
"to": "<not provided>",
"images": "<empty>",
"social": {
"twitter": "<not provided>",
"landing": "<not provided>",
"name": "<not provided>"
},
"mandrill": {
"tags": "<not provided>",
"merge": "<not provided>"
},
"styles": "<defaults>"
}
.send
vs .sendString
The only difference between .send
and .sendString
is that .send
takes the path to a file, rather than the template itself. .send
compiles the template and keeps it in a cache, while .sendString
compiles the template every time.
subject
The email subject.
preview
This is the line that most email clients show as the preview of the email message. It defaults to the subject line. Changing it is extremely encouraged.
to
These are the recipients of the email you're sending. Simply provide a single recipient's email address, or an array of email addresses.
images
If you want to provide the template with embedded images (other than the optional email header when creating the campaign
client) you can set images
to a list of file paths and names (to later reference them in your templates), as shown below.
[
{ name: 'housing', file: path.join(__dirname, 'housing.png') }
]
social
Social metadata used when sending an email can help build your brand. You can provide a twitter
handle, a name
for your brand, and a landing
page.
The name
is used as the name of the send address, as well as in the "Visit " link.
mandrill
Configuration specifically used by the Mandrill provider.
Mandrill allows you to add dynamic content to your templates, and this feature is supported by the default Mandrill provider in campaign
, out the box. Read more about merge variables.
mandrill.merge
Given that Mandrill's merge
API is fairly obscure, we process it in our provider, so that you can configure it assigning something like what's below to mandrill.merge
, which is cleaner than what Mandrill expects you to put together.
{
"locals": [{
"email": "someone@accounting.is",
"model": {
"something": "is a merge local for the guy with that email"
}
}],
"globals": [{
"these": "are merge globals for everyone"
}]
}
Mandrill lets you tag your emails so that you can find different campaigns later on. Read more about tagging. By default, emails will be tagged with the template name.
styles
Read about styles below.
There are two types of templates: the layout
, and the email's body
template. A default layout
is provided, so let's talk about the email templates first, and then the layout.
body
TemplatesThe body
template determines what goes in the message body. The options we used to configure our email are also used as the model for the body
template, as sometimes it might be useful to include some of that metadata in the model itself.
The API expects an absolute path to the body
template.
client.send(body, options, done);
Other than the options listed above, you can provide any values you want, and then reference those in the template.
layout
TemplateThe layout
has one fundamental requirement in order to be mildly functional, it should have a {{{body}}}
in it, so that the actual email's content can be rendered. Luckily the default layout
is good enough that you shouldn't need to touch it.
Purposely, the layout template isn't passed the full model, but only a subset, containing:
{
"_header": "<!!options._header>",
"subject": "<options.subject>",
"preview": "<options.preview>",
"generated": "<when>",
"body": "<html>",
"trapped": "<options.trapped>",
"social": "<options.social>",
"styles": "<options.style>"
}
In this case, the _header
variable would contain whether a header image was provided. Then, generated
contains the moment the email was rendered, passing the 'YYYY/MM/DD HH:mm, UTC Z'
format string to moment
. Lastly, trapped
contains the metadata extracted from the model when trap
is set to a truthy value, in the client options.
layout
These are the default styles
, and you can override them in the options
passed to client.send
.
{
"styles": {
"bodyBackgroundColor": "#eaeadf",
"bodyTextColor": "#505050",
"codeFontFamily": "Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif",
"fontFamily": "Helvetica",
"footerBackgroundColor": "#f4f4f4",
"headerColor": "#412917",
"horizontalBorderColor": "#dedede",
"layoutBackgroundColor": "#f3f4eb",
"layoutTextColor": "#808080",
"linkColor": "#e92c6c",
"quoteBorderColor": "#cbc5c0"
}
}
The default layout
supports an optional unsubscribe_html
merge variable, which can be filled out like below.
{
"merge": {
"locals": [{
"email": "someone@somewhere.com",
"model": {
"unsubscribe_html": "<a href='http://sth.ng/unsubscribe/hash_someone'>unsubscribe</a>"
}
}, {
"email": "someone@else.com",
"model": {
"unsubscribe_html": "<a href='http://sth.ng/unsubscribe/hash_someone_else'>unsubscribe</a>"
}
}]
}
}
That'd be a perfect use for merge variables, which were described above in the send options. Remember, those are just supported by Mandrill, though. Mandrill deals with merge variables after you make a request to their API, replacing them with the values assigned to each recipient.
To help you debug, an alternative provider
is available. Set it up like this:
var campaign = require('campaign');
var client = campaign({
provider: campaign.providers.console()
});
// build and send mails as usual
Rather than actually sending emails, you will get a lot of JSON output in your terminal. Useful!
There are a few different providers you can use. The default provider sends mails through Mandrill. There is also a console
logging provider, explained above, and a nodemailer
provider, detailed below.
nodemailer
To use with nodemailer
, simply use that provider.
var nodemailer = require('nodemailer');
var smtp = nodemailer.createTransport('SMTP', {
service: 'Gmail',
auth: {
user: 'gmail.user@gmail.com',
pass: 'userpass'
}
});
var campaign = require('campaign');
var client = campaign({
provider: campaign.providers.nodemailer({
transport: smtp,
transform: function (options) {
// add whatever options you want,
// or return a completely different object
}
})
});
// build and send mails as usual
That's that.
If the existing providers don't satisfy your needs, you may provide your own. The provider
option just needs to be an object with a send
method. For an example, check out the nodemailer
provider source code.
You can easily write your own campaign
provider, like this.
var campaign = require('campaign');
var client = campaign({
provider: {
send: function (model, done) {
// use the data in the model to send your email messages
}
}
});
// build and send mails as usual
If you decide to go for your own provider, campaign
will still prove useful thanks to its templating features.
MIT
1.1.1 Real Eel
trap
to true
will now simply not send any emails, periodFAQs
Compose responsive email templates easily, fill them with models, and send them out.
The npm package campaign receives a total of 0 weekly downloads. As such, campaign popularity was classified as not popular.
We found that campaign demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.