Using the EmailEngine API to send email

In this blog post, I'm walking through the required steps to register an account with EmailEngine and sending an email from that account.

Step 1. Register a new account

Register a new account with IMAP and SMTP settings (reference)

curl -XPOST "http://127.0.0.1:3000/v1/account" \
    -H "Authorization: Bearer f77cf263b70488..." \
    -H "Content-type: application/json" \
    -d '{
      "account": "example",
      "name": "Andris Reinman",
      "email": "andris@example.com",
      "imap": {
        "auth": {
          "user": "andris",
          "pass": "sercretpass"
        },
        "host": "mail.example.com",
        "port": 993,
        "secure": true
      },
      "smtp": {
        "auth": {
          "user": "andris",
          "pass": "secretpass"
        },
        "host": "mail.example.com",
        "port": 465,
        "secure": true
      }
    }'

Notes

  1. Token (f77cf263b70488....) was generated in EmailEngine's dashboard on the Access Tokens page. Read more.
  2. Be aware that if you are using any other port for SMPT than 465, then set secure to false

Expected result

{
  "account": "example",
  "state": "new"
}

Step 1. Send an email

Send an email by submitting an email structure to EmailEngine's submit endpoint (reference)

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>"
    }'

Expected result

{
  "response": "Queued for delivery",
  "messageId": "<99f7f0ec-90a1-caaf-698b-18e096c7679e@example.com>",
  "sendAt": "2021-12-23T10:22:31.312Z",
  "queueId": "4646ac53857fd2b2"
}

Notes

  1. Accepting the message for delivery does not mean that EmailEngine delivered the message. Listen for messageFailed and messageSent webhook notifications to see if EmailEngine was able to pass the message over to MTA or not
  2. You can't submit messages if EmailEngine is still performing initial sync for that account. You can check the current state of an account by requesting the account info and checking if the state property of the account is "connected" or not.

Webhook results

messageSent

EmailEngine managed to deliver the email to the MTA server. In this case, the webhooks should arrive pretty much immediately.

{
  "account": "example",
  "date": "2021-12-23T10:32:39.499Z",
  "event": "messageSent",
  "data": {
    "messageId": "<a00576bd-f757-10c7-26b8-885d7bbd9e83@example.com>",
    "response": "250 2.0.0 Ok: queued as 5755482356",
    "envelope": {
      "from": "andris@example.com",
      "to": [
        "andris@ethereal.email"
      ]
    }
  }
}

messageFailed

EmailEngine retries sending multiple times, so receiving the webhook takes a long time (EmailEngine sends the failure webhook once it has given up retrying the message).

{
  "account": "example",
  "date": "2021-12-23T11:58:50.181Z",
  "event": "messageFailed",
  "data": {
    "messageId": "<97ac5d9a-93c7-104b-8d26-6b25f8d644ec@example.com>",
    "queueId": "610c2c93e608bd37",
    "error": "Error: Invalid login: 535 5.7.8 Error: authentication failed: "
  }
}

While retrying, you can see the job entry on the Bull UI page under submit queue. The failed job should reside in the "delayed" section.

If you open that queue, you should see why the job is being retried.

Received message

Once the message is delivered, it should look like this:

Troubleshooting

Some email servers might not accept emails even if the username and password are correct. Notably Gmail, Outlook, and Yahoo. This happens when the email server detects that the sender might be a bot and suspects that the account might be used without permission. To overcome, use application-specific passwords or OAuth2 as these limitations do not apply when using OAuth2.