Mail

AdonisJs has first class support for sending email.

The Mail Provider supports a number of drivers including:

  • Smtp (smtp)

  • Spark Post (sparkpost)

  • Mailgun (mailgun)

  • Amazon SES (ses)

Setup

As the Mail Provider is not installed by default, we need to pull it from npm:

> adonis install @adonisjs/mail

Next, register the provider inside the start/app.js file:

start/app.js
const providers = [
  '@adonisjs/mail/providers/MailProvider'
]
Mail configuration is saved inside the config/mail.js file, which is created by the adonis install command when installing the Mail Provider.

Basic Example

Let’s start with the basic example of sending email on user registration:

start/routes.js
Route.post('user', 'UserController.store')
app/Controllers/Http/UserController.js
const Mail = use('Mail')

class UserController {

  async store ({ request }) {
    const data = request.only(['email', 'username', 'password'])
    const user = await User.create(data)

    await Mail.send('emails.welcome', user.toJSON(), (message) => {
      message
        .to(user.email)
        .from('<from-email>')
        .subject('Welcome to yardstick')
    })

    return 'Registered successfully'
  }
}

module.exports = UserController

Finally, create the emails/welcome.edge view file containing the HTML body:

resources/views/emails/welcome.edge
<h2> Hello {{ username }} </h2>
<p>
  Welcome to the yardstick club, here's your getting started guide
</p>

Mail API

Below is the list of methods you can use to send emails.

send(views, data, callback)

Send email using one or many Edge views:

await Mail.send('view', data, (message) => {
  message
    .from('')
    .to('')
})

The views argument can be a single view or array of views per content type:

await Mail.send(['welcome', 'welcome.text'])

In the example above, the welcome view is used for the HTML version of the email, while the welcome.text view is used for the plain text version.

If you’re using Edge as your template engine, you can also use ‑text instead of .text as the plain text body template suffix.

Using template suffixes, you can also set the mail body for Apple watch:

await Mail.send(['welcome', 'welcome.text', 'welcome.watch'])

raw(body, callback)

Use a raw string to send the mail (when the string is HTML the email HTML body will be set, otherwise just a plain text email will be sent):

await Mail.raw('plain text email', (message) => {
  message.from('[email protected]')
  message.to('[email protected]')
})

await Mail.raw('<h1> HTML email </h1>', (message) => {
  message.from('[email protected]')
  message.to('[email protected]')
})

Message API

Below is the list of methods you can use to build a mail message using the fluent message API.

to(address, [name])

Set to address:

message.to(user.email)

// with email and name both
message.to(user.email, user.name)

from(address, [name])

Set from address:

message.from('[email protected]')

// with email and name both
message.from('[email protected]', 'Yardstick')

cc(address, [name])

Add cc address to the email:

message.cc(user.email)

// with email and name both
message.cc(user.email, user.name)

bcc(address, [name])

Add bcc address to the email:

message.bcc(user.email)

// with email and name both
message.bcc(user.email, user.name)
You can call the above methods multiple times to define multiple addresses.

replyTo(address, [name])

Set replyTo email address:

message.replyTo('[email protected]')

inReplyTo(messageId)

Set email message id:

message.inReplyTo(someThread.id)

subject(value)

Set email subject:

message.subject('Welcome to yardstick')

text(value)

Manually set the plain text body for the email:

message.text('Email plain text version')

attach(filePath, [options])

Attach file(s) to the email:

message
  .attach(Helpers.tmpPath('guides/getting-started.pdf'))

Set custom file name:

message
  .attach(Helpers.tmpPath('guides/getting-started.pdf'), {
    filename: 'Getting-Started.pdf'
  })

attachData(data, filename, [options])

Attach raw data as a String, Buffer or Stream:

message.attachData('hello', 'hello.txt')

// buffer
message.attachData(new Buffer('hello'), 'hello.txt')

// stream
message.attachData(fs.createReadStream('hello.txt'), 'hello.txt')

embed(filePath, cid, [options])

Embed an image into the HTML body using a content id:

message.embed(Helpers.publicPath('logo.png'), 'logo')

Then inside the template, you can say:

<img src="cid:logo" />
Ensure the cid is unique for each image in a given email.

driverExtras(extras)

Pass an object of values to the current driver:

message.driverExtras({ campaign_id: 20 })

The Mail Provider passes the object through to the driver, and it is up to the driver to consume these values.

Switching Connections

The Mail Provider defines multiple connections inside the config/mail.js file:

config/mail.js
{
  connection: 'smtp',

  smtp: {},

  sparkpost: {
    driver: 'sparkpost',
    apiKey: Env.get('SPARKPOST_API_KEY'),
    extras: {}
  }
}

Using the above configuration, you could switch to the sparkpost connection via the connection method like so:

await Mail
  .connection('sparkpost')
  .send('view', data, (message) => {
  })

Drivers

Below are configuration instructions relating to each specific driver.

SES

The ses driver requires the aws-sdk package.

Ensure to install it via npm before using the ses driver:

> npm i aws-sdk

SparkPost

The sparkpost driver accepts an optional extras configuration object:

config/mail.js
{
  extras: {
    campaign_id: '',
    options: {}
  }
}

Check out SparkPost’s documentation to learn more about their available options.

You can also pass extras at runtime using the driverExtras method:

await Mail.send('view', data, (message) => {
  message.driverExtras({
    campaign_id: '',
    options: {}
  })
})

Mailgun

The mailgun driver accepts an optional extras configuration object:

config/mail.js
{
  extras: {
    'o:tag': '',
    'o:campaign': ''
  }
}

Check out Mailgun’s documentation to learn more about their available options.

You can also pass extras at runtime using the driverExtras method:

await Mail.send('view', data, (message) => {
  message.driverExtras({
    'o:tag': '',
    'o:campaign': ''
  })
})