Webhook events

Every event Mailyte will send to your endpoint, what it means, and whether it needs you to do anything.

Registering an endpoint, verifying signatures and surviving retries are covered in Receiving webhooks. This page is the catalogue.

The envelope

Every delivery has the same outer shape. Payload fields are snake_case throughout.

Delivery
{
  "id": "01JBT8XQ2M9WYC3K4F6R7S8T9V",
  "event": "email.bounced",
  "created_at": "2026-09-17T10:04:11.000000Z",
  "account": {
    "organization_id": "01JBT8XQ2M9WYC3K4F6R7S8T9W"
  },
  "data": {
    "message_id": "<01JBT8XQ2M@yourdomain.com>",
    "recipient": "ada@example.com",
    "domain": "yourdomain.com",
    "dsn": "5.1.1",
    "reason": "Mailbox does not exist",
    "provider": "Gmail"
  }
}

id is stable across retries — key your idempotency on it. provider names the receiving platform where we can identify it, which makes "are we only bouncing at Microsoft" a question you can answer.

Events

  • email.acceptedinfo

    Fires when We have taken the message and queued it for delivery.

    What to do Nothing. It is a receipt, not an outcome.

  • email.submittedinfo

    Fires when The message has been handed to the sending infrastructure.

    What to do Nothing.

  • email.sentinfo

    Fires when The message has left our network.

    What to do Nothing — wait for email.delivered.

  • email.deliveredinfo

    Fires when The receiving server accepted the message.

    What to do Mark as sent. Note this means accepted by the server, not read by a person, and not necessarily in the inbox rather than the spam folder.

  • email.deferredwarning

    Fires when Temporarily refused — greylisting, a full mailbox, rate limiting at their end. We will retry.

    What to do Nothing. Sending again yourself puts two copies in flight and makes a temporary problem a reputation one.

  • email.bouncederror

    Fires when Permanently refused. No such mailbox, or the domain does not accept mail.

    What to do Stop sending to this address. It is added to your suppression list automatically.

  • email.rejectederror

    Fires when The receiving server refused the message outright, often for policy or content reasons.

    What to do Read the reason. Repeated rejections from one provider point at a content or authentication problem rather than a bad address.

  • email.droppederror

    Fires when We refused to send it — almost always because the recipient is suppressed.

    What to do Check your suppression list. This event exists so a refused send leaves a trace instead of vanishing.

  • email.complainederror

    Fires when The recipient marked the message as spam.

    What to do Treat as a permanent opt-out from everything, immediately. Complaints damage deliverability at volumes far below what most people expect.

  • delivery.complaintwarning

    Fires when A feedback loop report arrived from a receiving provider.

    What to do Same as a complaint: stop sending to that address.

  • spam.reportedwarning

    Fires when Our own filtering classified an inbound message as spam.

    What to do Only relevant if you are receiving mail through Mailyte.

  • email.inboundinfo

    Fires when A message arrived at one of your mailboxes.

    What to do Process it. This is the event to build an inbound pipeline on — it is distinct from email.delivered, which is about mail you sent.

  • tracking.openinfo

    Fires when A tracking pixel in an HTML message was loaded.

    What to do Treat with caution — see below.

  • tracking.clickinfo

    Fires when A tracked link was followed.

    What to do Treat with caution — see below.

  • tracking.unsubscribewarning

    Fires when The recipient used an unsubscribe link.

    What to do Honour it everywhere, not just in the campaign it came from. They are suppressed automatically.

  • queue.message.failederror

    Fires when A message could not be processed at all.

    What to do Investigate. This is our side failing, not a recipient refusing.

  • storage.quota.warningwarning

    Fires when A mailbox is approaching its quota.

    What to do Raise the quota or prompt the holder to clear space, before mail starts bouncing.

  • storage.quota.exceedederror

    Fires when A mailbox is full and is refusing new mail.

    What to do Raise the quota. Incoming mail is being rejected right now.

Inbound mail is its own event

Mail arriving at your mailboxes fires email.inbound. Mail you sent reaching its destination fires email.delivered.

They were once conflated, and inbound mail was emitted as email.delivered — which made a "received" count that sat at zero for ever while mail was plainly arriving. If you integrated against the old behaviour, this is the change to check.

Opens and clicks are unreliable

Not a limitation of our implementation — a limitation of the technique. Open tracking needs a remote image to load, and:

  • privacy proxies fetch it on the recipient's behalf, sometimes for mail they never open;
  • many clients block remote images, so a real open records nothing;
  • security scanners follow links, producing clicks nobody made.

We have measured this here: a 30-day window once contained 499 opens and 36 clicks that were, on inspection, entirely our own infrastructure and no human at all.

Use them as a weak signal about a population. Never as evidence about a person.