Sending Email with the EmailEngine API

TL;DR
Register the mailbox with/v1/account
, wait until it’sconnected
, then POST your message payload to/v1/account/:id/submit
. EmailEngine queues the message, handles retries, and notifies you via webhooks.
Why it matters
When your SaaS needs to send email on behalf of a customer, direct SMTP is brittle: every provider has its own auth, rate limits, retries, and error codes. EmailEngine shields you from that complexity by exposing a single REST endpoint that proxies the customer’s mailbox. You get consistent JSON responses and robust retry logic.
Step‑by‑step
1. Register the account
Endpoint: POST /v1/account
$ curl -XPOST "http://127.0.0.1:3000/v1/account" \
-H "Authorization: Bearer <your‑token>" \
-H "Content-Type: application/json" \
-d '{
"account": "example",
"name": "Andris Reinman",
"email": "andris@example.com",
"imap": {
"auth": { "user": "andris", "pass": "secretpass" },
"host": "mail.example.com",
"port": 993,
"secure": true
},
"smtp": {
"auth": { "user": "andris", "pass": "secretpass" },
"host": "mail.example.com",
"port": 465,
"secure": true
}
}'
Expected response:
{ "account": "example", "state": "new" }
⚠️ Heads‑up – If you use an SMTP port other than 465, set "secure": false
.
2. Submit the message
Endpoint: POST /v1/account/:id/submit
Full docs: Message submission
$ curl -XPOST "http://127.0.0.1:3000/v1/account/example/submit" \
-H "Authorization: Bearer <your‑token>" \
-H "Content-Type: application/json" \
-d '{
"to": [{ "name": "Ethereal", "address": "andris@ethereal.email" }],
"subject": "Test message",
"text": "Hello from myself!",
"html": "<p>Hello from myself!</p>"
}'
Expected response (queued, not yet delivered):
{
"response": "Queued for delivery",
"messageId": "<99f7f0ec-90a1-caaf-698b-18e096c7679e@example.com>",
"sendAt": "2025-05-14T10:22:31.312Z",
"queueId": "4646ac53857fd2b2"
}
💡 Tip – Submission is rejected while EmailEngine is still performing the initial sync. Poll/v1/account/:id
untilstate
becomes"connected"
.
3. Listen for webhooks
EmailEngine pushes delivery status updates to the webhook URL you configured under Settings → Webhooks.
messageSent
Delivered to the outbound MTA.
{
"account": "example",
"date": "2025-05-14T10: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" ]
}
}
}
messageDeliveryError
Emitted after every failed delivery attempt. EmailEngine retries automatically until delivery succeeds or the maximum number of attempts is reached. You’ll receive one messageDeliveryError
webhook per attempt.
{
"serviceUrl": "http://127.0.0.1:3000",
"account": "example",
"date": "2025-05-14T15:07:35.832Z",
"event": "messageDeliveryError",
"data": {
"queueId": "1833c8a88a86109a1bf",
"envelope": {
"from": "andris@example.com",
"to": [ "andris@ethereal.email" ]
},
"messageId": "<29e26263-7125-ff56-4f80-83a5cf737d5e@ekiri.ee>",
"error": "400 Message Not Accepted",
"errorCode": "EPROTOCOL",
"smtpResponseCode": 400,
"job": {
"attemptsMade": 1,
"attempts": 10,
"nextAttempt": "2025-05-14T15:07:45.465Z"
}
}
}
messageFailed
Raised once EmailEngine gives up retrying.
{
"account": "example",
"date": "2025-05-14T11: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: "
}
}
Common pitfalls
⚠️ Authentication quirks – Gmail, Outlook, and Yahoo may refuse SMTP logins that look like bots. Switch to OAuth2 or an app‑specific password.
💡 Timeouts – Heroku dynos cut idle sockets. Either move off the platform or bump the dyno size.