Webhooks

Using webhooks with EmailEngine

Event list

These are the available events that EmailEngine sends webhooks for.

Type Name Description
messageNew New Email A new email is found from a folder (new email)
messageDeleted Deleted Message A previously present email is not found from a folder (deleted email)
messageUpdated Flag Change Email flags are changed (flag change)
messageMissing Missing Message A message that should exist, was not found. Indicates syncing errors.
messageSent Message Accepted Queued email is accepted by the MTA server (message accepted)
messageDeliveryError SMTP error EmailEngine failed to send an email to the SMTP server. This action might be retried. (SMTP error)
messageFailed Message Bounced EmailEngine fails to deliver a queued email to the MTA server (message bounced)
messageBounce Bounce Received Bounce response email is received (bounce received)
messageComplaint Complaint received FBL complaint was detected
mailboxReset Mailbox Reset UIDValidity for a folder changes (mailbox reset)
mailboxDeleted Folder Deleted A previously present folder is not found (folder deleted)
mailboxNew New Folder A new folder is found (new folder)
authenticationError Authentication Failure EmailEngine fails to authenticate an email account
authenticationSuccess Authentication Success An email account is successfully authenticated
connectError Connection Failure EmailEngine fails to establish a connection to an email server
accountAdded Account added a new email account was registered with EmailEngine
accountInitialized Account initialized Account has been connected and the first sync is completed
accountDeleted Account deleted an email account was removed from EmailEngine
trackOpen Email open tracked recipient opened an email
trackClick Link click tracked recipient clicked on a link
listUnsubscribe Recipient unsubscribed recipient unsubscribed from a list
listSubscribe Recipient subscribed recipient re-subscribed to a list

messageNew

A new message was added to a folder. This event is generated by incoming emails, uploaded emails, and emails moved or copied from one folder to another. IMAP does not distinguish "incoming" emails from messages that are added to a folder by other means.

NB! Content text webhook setting is enabled for this example, so there are data.text.plain and data.text.html fields set. The default would be to not include content text in the payload. To enable text processing, you can set it in the UI with ConfigurationWebhooksText content"Include text content in new email webhooks" or by setting notifyText to true with the Settings API.

{
  "serviceUrl": "https://emailengine-dev.apps.srv.dev",
  "account": "postalsys",
  "date": "2023-03-14T11:13:10.609Z",
  "path": "[Gmail]/All Mail",
  "specialUse": "\\All",
  "event": "messageNew",
  "data": {
    "id": "AAAAAQABDFI",
    "uid": 68690,
    "path": "[Gmail]/All Mail",
    "emailId": "1760341395373354319",
    "threadId": "1760341395373354319",
    "date": "2023-03-14T11:12:45.000Z",
    "flags": [],
    "labels": [
      "\\Important",
      "\\Inbox"
    ],
    "unseen": true,
    "size": 8271,
    "subject": "Impressed by the new features of EmailEngine!",
    "from": {
      "name": "Andris Reinman",
      "address": "andris.reinman@gmail.com"
    },
    "replyTo": [
      {
        "name": "Andris Reinman",
        "address": "andris.reinman@gmail.com"
      }
    ],
    "sender": {
      "name": "Andris Reinman",
      "address": "andris.reinman@gmail.com"
    },
    "to": [
      {
        "name": "",
        "address": "andris@postalsys.com"
      }
    ],
    "messageId": "<CAPacwgwKMETwvftKuQyieSKmp1C+NJcZtqjZ2pSALZkjB-CCbQ@mail.gmail.com>",
    "text": {
      "id": "AAAAAQABDFKTkaExkaEykA",
      "encodedSize": {
        "plain": 1535,
        "html": 1630
      },
      "plain": "Dear Postal Systems OÜ,\n\nI hope this email finds you well. I am writing to express my excitement and\nadmiration for the new features of EmailEngine. As a regular user of email\nservices, I have found it difficult to manage my multiple email accounts on\ndifferent apps. However, EmailEngine has proved to be a game-changer in\nthis regard.\n\nI am amazed by how EmailEngine allows other apps to access regular email\naccounts, making the process of managing emails much easier and efficient.\nThe user-friendly interface and advanced security features make it a\nreliable choice for anyone who wants to manage their emails in a\nhassle-free manner.\n\nOne of the most impressive features of EmailEngine is its compatibility\nwith different email service providers. It seamlessly integrates with\nGmail, Outlook, Yahoo, and many other popular email services, allowing\nusers to manage their emails in one place without having to switch between\ndifferent apps.\n\nFurthermore, the customizable API and SDKs of EmailEngine make it possible\nfor developers to integrate it into their apps, enabling their users to\naccess their email accounts without leaving the app. This feature is not\nonly convenient but also saves time and enhances the user experience.\n\nOverall, I am thoroughly impressed by the new features of EmailEngine, and\nI believe it is a significant step towards making email management more\naccessible and efficient. Thank you for providing such a valuable service\nto users like me.\n\nBest regards,\nAndris\n",
      "html": "<div dir=\"ltr\">Dear Postal Systems OÜ,<br><br>I hope this email finds you well. I am writing to express my excitement and admiration for the new features of EmailEngine. As a regular user of email services, I have found it difficult to manage my multiple email accounts on different apps. However, EmailEngine has proved to be a game-changer in this regard.<br><br>I am amazed by how EmailEngine allows other apps to access regular email accounts, making the process of managing emails much easier and efficient. The user-friendly interface and advanced security features make it a reliable choice for anyone who wants to manage their emails in a hassle-free manner.<br><br>One of the most impressive features of EmailEngine is its compatibility with different email service providers. It seamlessly integrates with Gmail, Outlook, Yahoo, and many other popular email services, allowing users to manage their emails in one place without having to switch between different apps.<br><br>Furthermore, the customizable API and SDKs of EmailEngine make it possible for developers to integrate it into their apps, enabling their users to access their email accounts without leaving the app. This feature is not only convenient but also saves time and enhances the user experience.<br><br>Overall, I am thoroughly impressed by the new features of EmailEngine, and I believe it is a significant step towards making email management more accessible and efficient. Thank you for providing such a valuable service to users like me.<br><br>Best regards,<br>Andris<br></div>\n",
      "hasMore": false
    },
    "category": "primary",
    "isAutoReply": false,
    "seemsLikeNew": true,
    "messageSpecialUse": "\\Inbox",
    "summary": {
      "id": "chatcmpl-6twsSdxRdTVq8uWPfbsdWSgQViJI3",
      "tokens": 512,
      "summary": "Andris is impressed with the new features of EmailEngine and finds it easier to manage his multiple email accounts on different apps with EmailEngine. He appreciates its user-friendly interface, advanced security features, compatibility with different email service providers, customizable API and SDKs, and its ability to allow other apps to access regular email accounts.",
      "sentiment": "positive"
    }
  },
  "_route": {
    "id": "AAABhpMgNhsAAAAE"
  }
}

Field definitions

  • _route is present if the webhook was sent via a webhook router.
  • data.category is present for Gmail Inbox emails if Resolve Gmail categories option is enabled in the Service → Labs configuration section. The value indicates the Gmail category tab of the incoming email. See below ↓ for more details.
  • data.seemsLikeNew is a probabilistic indicator if EmailEngine has seen this email before or not. This is correct around 99%.
  • specialUse indicates the special use folder the email was found from. NB! For most Gmail account emails, this is \All, so check the messageSpecialUse property for better indication
  • data.messageSpecialUse indicates the special use folder this email belongs to. For most emails, this is the same as specialUse property, but for Gmail accounts, where emails mostly reside in the \All folder, it is different.
  • data.isAutoReply indicates if the email is an auto-reply email (out-of-office, bounce, etc)
  • data.summary is the summary info provided by ChatGPT if OpenAI integration is enabled in the Service → Labs configuration section.

Gmail tab category

Gmail sorts incoming emails into different categories like promotions, social, and primary and displays emails under these category tabs. For IMAP, all these emails still look like regular INBOX folder emails. EmailEngine can resolve the category of incoming emails and include this information in the payload of the messageNew webhook.

Category resolving is not enabled by default. To enable it, navigate to Configuration -> Service, and then to the Labs section. Mark the "Resolve Gmail categories" checkbox, and save the settings.

Now, whenever an email lands in the Inbox of an email account that EmailEngine tracks, the messageNew webhook for that email will include a property called category, and the value is one of the following: social, promotions, updates, forums, and primary.

messageDeleted

A message was deleted from a folder. This happens when a message was either deleted or moved to another folder.

{
  "account": "pangalink",
  "date": "2022-01-17T11:54:02.089Z",
  "path": "[Gmail]/All Mail",
  "specialUse": "\\All",
  "event": "messageDeleted",
  "data": {
    "id": "AAAAAQAANJc",
    "uid": 13463
  }
}

messageUpdated

This event is fired when a change is detected with a message. Most commonly, when the user marks a message as read or unread.

{
  "account": "pangalink",
  "date": "2022-01-17T11:56:13.146Z",
  "path": "[Gmail]/All Mail",
  "specialUse": "\\All",
  "event": "messageUpdated",
  "data": {
    "id": "AAAAAQAANJY",
    "uid": 13462,
    "changes": {
      "flags": {
        "added": [
          "\\Seen"
        ]
      }
    }
  }
}

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@ekiri.ee>",
    "response": "250 2.0.0 Ok: queued as 5755482356",
    "envelope": {
      "from": "andris@ekiri.ee",
      "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@ekiri.ee>",
    "queueId": "610c2c93e608bd37",
    "error": "Error: Invalid login: 535 5.7.8 Error: authentication failed: "
  }
}

messageComplaint

EmailEngine found an ARF formatted FBL report from the Inbox folder. If such an email is found, then EmailEngine parses it and posts parsed information as the messageComplaint webhook.

{
  "serviceUrl": "http://127.0.0.1:3000",
  "account": "example",
  "date": "2022-09-27T12:33:42.635Z",
  "event": "messageComplaint",
  "data": {
    "complaintMessage": "AAAAAQAABvE",
    "arf": {
      "source": "Hotmail",
      "feedbackType": "abuse",
      "abuseType": "complaint",
      "originalRcptTo": [
        "recipient@hotmail.co.uk"
      ],
      "sourceIp": "1.2.3.4",
      "arrivalDate": "2021-10-22T13:04:36.017Z"
    },
    "headers": {
      "messageId": "<67d3846d-b819-9c54-5053-a81fdc432425@example.com>",
      "from": "user@example.com",
      "to": [
        "recipient@hotmail.co.uk"
      ],
      "subject": "Hello world",
      "date": "2021-10-22T16:04:33.000Z"
    }
  }
}

NB! included fields depend on the reporting server. Sometimes important information like the source email Message-ID value might be missing.

messageDeliveryError

EmailEngine retries sending multiple times. For every failing try a messageDeliveryError is sent.

{
  "serviceUrl": "http://127.0.0.1:3000",
  "account": "example",
  "date": "2022-09-14T15:07:35.832Z",
  "event": "messageDeliveryError",
  "data": {
    "queueId": "1833c8a88a86109a1bf",
    "envelope": {
      "from": "andris@ekiri.ee",
      "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": "2022-09-14T15:07:45.465Z"
    }
  }
}

messageBounce

A new bounce response message was found from the account. The bounce data includes messageId value but no id value, so you have to look up the bounced message using the Message-ID header value.

If multiple recipients for the same message bounce, you get a separate bounce event for each of these recipients.

{
  "account": "pangalink",
  "date": "2021-11-28T10:17:29.728Z",
  "event": "messageBounce",
  "data": {
    "bounceMessage": "AAAAAQAABWw",
    "recipient": "failed.recipient@example.com",
    "action": "failed",
    "response": {
      "source": "smtp",
      "message": "550 5.1.1 <failed.recipient@example.com>: Recipient address rejected: User unknown in relay recipient table",
      "status": "5.1.1"
    },
    "mta": "mx.example.com",
    "queueId": "BFC608226A",
    "messageId": "<4dbe4a40f37e9c2ba5b25912bc7c8997@example.com>"
  }
}

Some fields might be missing from a bounce webhook depending on how EmailEngine can parse the information out from the bounce.

trackOpen

Email client loaded the open tracking beacon. This only works if the email client loads external images. There might be false positives, for example, when a web-based email client caches linked images.

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

trackClick

A tracked link was clicked. False positives might occur when security software scans links in an incoming email.

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

listUnsubscribe

A recipient clicked on the unsubscribe link, or the email client posted the one-click unsubscribe request.

{
  "account": "example",
  "date": "2022-03-24T08:27:24.572Z",
  "event": "listUnsubscribe",
  "data": {
    "recipient": "recipient@example.com",
    "messageId": "<49b6cdb1-5d43-e100-0833-bd61867b7bb3@example.com>",
    "listId": "my-customers-list",
    "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"
  }
}

Webhook headers

You can set custom headers for webhook requests with the webhooksCustomHeaders setting, or from the webhook setting page in EmailEngine's admin dashboard.

In addition to custom headers, EmailEngine also includes some additional debugging headers, as shown below.

Header Example value Description
X-EE-Wh-Event-Id "af8435d9-ceee-4715-be71-08ac9d2dc04a" UUID assigned to the event. All webhook instances of the same event have the same event ID
X-EE-Wh-Custom-Route "AAABiL8tBKsAAAAG" Id of the custom webhook route used for this webhook
X-EE-Wh-Queued-Time "0s" How much time was this webhook queued
X-EE-Wh-Attempts-Made "1" The attempt counter for this webhook. Anything over 1 means that posting this webhook failed previously
X-EE-Wh-Id "907889" ID of the queued webhook entry

Webhook retries

EmailEngine makes up to 10 webhook delivery attempts before it considers a webhook payload undeliverable.

EmailEngine makes retry attempts with an exponential backoff strategy. The delay is 5000ms, and the formula to calculate the delay between attempts is the following:

2 ^ (attempts - 1) * delay milliseconds

Webhook jobs can be found from the notify queue (Tools → Arena → notify).

You can find failed webhooks that are yet to be retried from the Delayed job queue section and undeliverable webhooks from the Failed section. By default, EmailEngine does not store failed jobs. You can set the number of Completed/Failed jobs to keep in the Configuration → Service → Queue Settings configuration section.