Sending emails

How to send emails using EmailEngine

EmailEngine makes it possible to send emails using the registered accounts' SMTP servers and external sending services.

When sending an email, EmailEngine first queues the email for delivery. Once the email has been queued, EmailEngine would then try to transfer that message to the accounts' SMTP server or sending service.

While you obviously could do this directly, using EmailEngine means you do not have to store and manage the credentials of the email accounts. All you need is access to EmailEngine and to know the account ID you want to send the email from.

See also – sending emails using Email Templates and mail-merge.

API

Sending emails using the API

You can send emails through a specific email account using the submit API endpoint.

curl -XPOST "http://127.0.0.1:3000/v1/account/example/submit" \
    -H "Authorization: Bearer f77cf263b70488c7a35bf1539fd544a81a88711ff74326ce9793022df08d91b9" \
    -H "Content-type: application/json" \
    -d '{
      "from": {
        "name": "Andris Reinman",
        "address": "andris@example.com"
      },
      "to": [
        {
          "name": "Ethereal",
          "address": "andris@ethereal.email"
        }
      ],
      "subject": "Test message",
      "text": "Hello from myself!",
      "html": "<p>Hello from myself!</p>"
    }'

TIP: The from address in the request payload is optional. EmailEngine will use the account's registered email and name if it is not set.

The response for a queued delivery includes the queue ID (you can use it to cancel the delivery).

{
  "response": "Queued for delivery",
  "messageId": "<78aa92af-67c9-4130-b1bf-c22feb2ec3f6@example.com>",
  "sendAt": "2022-03-24T10:23:38.196Z",
  "queueId": "17fbb7408d44367d9b7"
}

Raw message

To send a prepared RFC822 formatted email message, you can provide it as a base64 encoded raw property value. Unless you specify the envelope property, recipient addresses are derived from email headers.

The following snippet creates the base64 raw value from a RFC822 formatted string value and submits the email for delivery.

curl -XPOST "http://127.0.0.1:3000/v1/account/example/submit" \
    -H "Authorization: Bearer f77cf263b70488c7a35bf1539fd544a81a88711ff74326ce9793022df08d91b9" \
    -H "Content-type: application/json" \
    -d "{
      \"raw\" : \"` echo 'From: andris@example.com
To: andris@ethereal.email
Subject: test message
Mime-Version: 1.0

Hello world!
' | base64`\"
    }"

SMTP

Sending via the bundled SMTP interface

To use the bundled SMTP interface, you must first enable it from the SMTP Interface configuration page.

You can then configure EmailEngine as the SMTP server for your email sending library. SMTP username is the account ID, and password is the SMTP password field value from the SMTP Server configuration page. The bundled SMTP server does not support encryption so make sure you do not configure tls/ssl settings.

EmailEngine responds the queue ID and the expected delivery time in the SMTP server response.

250 Message queued for delivery as 17fbb0a97504803a15a (2022-03-24T08:28:27.856Z)

Below you can find example configurations for different email client libraries.

Nodemailer

const transporter = nodemailer.createTransport({
    host: 'localhost',
    port: 2525,
    auth: {
        user: 'example',
        pass: 'a57518a9e8858187463d53d5b7d3aa0c'
    }
});

PHPMailer

$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'localhost';
$mail->SMTPAuth = true;
$mail->Username = 'example';
$mail->Password = 'PUg6PzUe3ErkAKUqJ6';
$mail->SMTPSecure = 'a57518a9e8858187463d53d5b7d3aa0c';
$mail->Port = 2525;

SwiftMailer

$transport = (new Swift_SmtpTransport('localhost', 2525))
  ->setUsername('example')
  ->setPassword('a57518a9e8858187463d53d5b7d3aa0c');

OAuth2

Regular Gmail accounts

Follow the guide for setting up OAuth2 with Gmail here.

Gmail service accounts

Follow the guide for setting up OAuth2 service accounts with Gmail here.

Hotmail/Outlook/MS365

Follow the guide for setting up OAuth2 for Microsoft accounts here.

Open and click tracking

Tracking user action events

EmailEngine supports basic open and clicks tracking. By default, tracking is disabled, and all email messages are sent unmodified. If you enable tracking, then EmailEngine rewrites HTML content of the emails so that all links would be redirected through EmailEngine. Whenever a user clicks on such a link, EmailEngine then sends a webhook notification about it.

Navigate to the Service configuration page and check the "Track opens and clicks" checkbox to enable tracking by default. Also, make sure that EmailEngine is configured to send webhooks for the "trackOpen" and "trackClick" events on the Webhooks configuration page.

You can manage tracking in the message level by using trackingEnabled API option or X-EE-Tracking-Enabled SMTP header.

Using the trackingEnabled option:

curl -XPOST "http://127.0.0.1:3000/v1/account/example/submit" \
    -H "Authorization: Bearer f77cf263b70488c7a35bf1539fd544a81a88711ff74326ce9793022df08d91b9" \
    -H "Content-type: application/json" \
    -d '{
      "from": {
        "name": "Andris Reinman",
        "address": "andris@example.com"
      },
      ...
      "trackingEnabled": true
    }'

Using X-EE-Tracking-Enabled message header:

From: Andris Ethereal <andris@example.com>
To: Andris Ethereal <andris@ethereal.email>
Subject: Tracking test
Message-ID: <2d4696ea-cb47-7af4-0bc3-81ea7a8008be@pangalink.net>
Date: Thu, 24 Mar 2022 08:28:27 +0000
MIME-Version: 1.0
X-EE-Tracking-Enabled: true

Tracking Webhooks

EmailEngine sends trackOpen webhooks whenever the tracking beacon is loaded and trackClick whenever a tracking link is clicked.

NB! Both events might include false positives. Webmail clients that cache or mask included images might trigger trackOpen webhooks, and security scanners that scan incoming emails for malicious links might trigger the trackClick webhooks.

Webhooks always include the Message-ID header value but not the internal identifier for EmailEngine messages. EmailEngine does not store this information and cannot match user action events against specific emails in the Sent Mail folder (this behavior might change in the future).

trackOpen

Email client loaded the open tracking beacon.

{
  "account": "example",
  "date": "2022-03-24T08:28:32.992Z",
  "event": "trackOpen",
  "data": {
    "messageId": "<2d4696ea-cb47-7af4-0bc3-81ea7a8008be@example.com>",
    "remoteAddress": "1.2.3.4",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36"
  }
}

Be aware that open tracking can be extremely misleading. The industry standard for open tracking is to include a beacon image in the email HTML code. Modern email clients often do not load remote images at all or use image preloading.

trackClick

A tracked link was clicked.

{
  "account": "example",
  "date": "2022-03-24T08:27:24.572Z",
  "event": "trackClick",
  "data": {
    "messageId": "<49b6cdb1-5d43-e100-0833-bd61867b7bb3@example.com>",
    "url": "https://google.com/",
    "remoteAddress": "1.2.3.4",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36"
  }
}

Delivery delay

Send emails at a specific time

You can schedule sending emails at a specific time. In that case, EmailEngine would queue the message but would not try to transfer it to the account's SMTP server until the requested time.

Using the sendAt option:

curl -XPOST "http://127.0.0.1:3000/v1/account/example/submit" \
    -H "Authorization: Bearer f77cf263b70488c7a35bf1539fd544a81a88711ff74326ce9793022df08d91b9" \
    -H "Content-type: application/json" \
    -d '{
      "from": {
        "name": "Andris Reinman",
        "address": "andris@example.com"
      },
      ...
      "sendAt": "2023-07-08T07:06:34.336Z"
    }'

Using X-EE-Send-At message header:

From: Andris Ethereal <andris@example.com>
To: Andris Ethereal <andris@ethereal.email>
Subject: Tracking test
Message-ID: <2d4696ea-cb47-7af4-0bc3-81ea7a8008be@pangalink.net>
Date: Thu, 24 Mar 2022 08:28:27 +0000
MIME-Version: 1.0
X-EE-Send-At: 2023-07-08T07:06:34.336Z

SMTP gateways

Send emails through an external service

By default, EmailEngine uses the account's SMTP server to send emails. Sometimes this might not be enough. For example, when you need to send a larger volume of emails. For these use cases, you can skip the account's SMTP server and use a dedicated sending service like Sendgrid, Mailgun, Postmark, AWS SES, or others.

First, register the gateway using the API.

curl -XPOST "http://127.0.0.1:3000/v1/gateway" \
  -H "Authorization: Bearer f77cf263b70488..." \
  -H "Content-type: application/json" \
  -d '{
      "gateway": "sendgrid",
      "name": "Sendgrid",
      "user": "apikey",
      "pass": "<YOUR_API_KEY>",
      "host": "smtp.sendgrid.net",
      "port": 465,
      "secure": true
    }'

Next, send an email from an email account, and specify the gateway option for routing.

curl -XPOST "http://127.0.0.1:3000/v1/account/example/submit" \
  -H "Authorization: Bearer f77cf263b70488c7a35bf1539fd544a81a88711ff74326ce9793022df08d91b9" \
  -H "Content-type: application/json" \
  -d '{
    "from": {
      "name": "Andris Reinman",
      "address": "andris@example.com"
    },
    "to": [
      {
        "name": "Ethereal",
        "address": "andris@ethereal.email"
      }
    ],
    "subject": "Test message",
    "text": "Hello from myself!",
    "html": "<p>Hello from myself!</p>",
    "gateway": "sendgrid"
  }'

SMTP settings do not need to be configured for the account when using gateways to send emails.

Outbox

Managing queued emails

EmailEngine allows you to list and delete emails that have been queued but are not yet transferred to the account's SMTP server. Outbox includes all emails that are scheduled to be delivered in the future, and it also contains emails that should have been sent but for whatever reason are not – for example, the SMTP server is currently not accessible.

Outbox is global as it includes queued emails for all accounts. It is not account-specific.

You can access the Outbox using the outbox API endpoints.

Bounces

You can read about detecting and handling bounces from here.

Replies and forwarding

EmailEngine includes helpers that mimic regular email clients when replying or forwarding emails. Read about it here.