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": "[email protected]"
      },
      "to": [
        {
          "name": "Ethereal",
          "address": "[email protected]"
        }
      ],
      "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": "<[email protected]>",
  "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: [email protected]
To: [email protected]
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 provides basic tracking features for email opens and clicks. By default, this tracking is disabled, and emails are sent unmodified. When tracking is enabled, EmailEngine rewrites the HTML content of outgoing emails, routing all links through EmailEngine’s tracking system. When a user clicks on a tracked link, EmailEngine generates a webhook notification.

Enabling Tracking

To enable tracking by default:

  1. Navigate to the Service Configuration page: Locate the "Sent Email Tracking" and mark the listed checkboxes. This will enable tracking for all outgoing emails unless overridden at the message level.

  2. Configure Webhooks: Ensure that EmailEngine is set up to send webhooks for trackOpen and trackClick events. This configuration can be managed on the Webhooks configuration page.

Managing Tracking at the Message Level

Tracking can be managed on a per-message basis using the trackingEnabled API option or the X-EE-Tracking-Enabled SMTP header. Additionally, you can configure tracking for clicks and opens separately with the trackClicks and trackOpens options.

Using API Options: trackClicks and trackOpens

To enable tracking for a specific message, include the trackClicks and trackOpens options in your API request:

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": "[email protected]"
      },
      ...
      "trackClicks": true,
      "trackOpens": true
    }'

This will enable tracking for both opens and clicks for the specified email.

Using SMTP Header: X-EE-Tracking-Enabled

Alternatively, you can enable tracking by adding the X-EE-Tracking-Enabled header to your email message:

From: Andris Ethereal <[email protected]>
To: Andris Ethereal <[email protected]>
Subject: Tracking test
Message-ID: <[email protected]>
Date: Thu, 24 Mar 2022 08:28:27 +0000
MIME-Version: 1.0
X-EE-Tracking-Enabled: true

This will enable tracking for that particular email.

Tracking Webhooks

EmailEngine sends webhooks for the following events:

  1. trackOpen: Triggered when the tracking beacon is loaded (i.e., when the email is opened).
  2. trackClick: Triggered when a user clicks on a tracked link.

Important Note: Both trackOpen and trackClick events might include false positives. For instance, webmail clients that cache images may trigger trackOpen events even if the user hasn’t explicitly opened the email. Similarly, security systems that scan emails for malicious links might trigger trackClick events.

trackOpen Webhook Example

Here is a sample webhook payload for an trackOpen event:

{
  "account": "example",
  "date": "2022-03-24T08:28:32.992Z",
  "event": "trackOpen",
  "data": {
    "messageId": "<[email protected]>",
    "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"
  }
}

Caution: Open tracking relies on a beacon image embedded in the email’s HTML. Many modern email clients block or pre-load images, which can lead to inaccurate tracking data.

trackClick Webhook Example

Here is a sample webhook payload for a trackClick event:

{
  "account": "example",
  "date": "2022-03-24T08:27:24.572Z",
  "event": "trackClick",
  "data": {
    "messageId": "<[email protected]>",
    "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"
  }
}

Considerations

  • Webhooks include the Message-ID of the email but do not include EmailEngine's internal identifier for the message. EmailEngine currently does not track this information, so matching webhook events to specific emails in the Sent Mail folder is not possible at this time (this may be updated in future versions).

  • If you prefer not to use your EmailEngine instance domain in tracking links (e.g., https://your-email-engine/tracking-info) and instead use customer-specific domain names (e.g., https://your-service.customer.tld/tracking-info), you can specify the baseUrl property in the /submit payload. You can set it like this: "baseUrl": "https://your-service.customer.tld". Just ensure that the domain points to your EmailEngine installation and that the HTTPS certificates are correctly configured and working.

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": "[email protected]"
      },
      ...
      "sendAt": "2023-07-08T07:06:34.336Z"
    }'

Using X-EE-Send-At message header:

From: Andris Ethereal <[email protected]>
To: Andris Ethereal <[email protected]>
Subject: Tracking test
Message-ID: <[email protected]>
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": "[email protected]"
    },
    "to": [
      {
        "name": "Ethereal",
        "address": "[email protected]"
      }
    ],
    "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.