Inbound email to webhook compared: Resend, Mailgun, SendGrid, Postmark, Cloudflare and MarkRelay

What lands at your endpoint when an email arrives, as each provider documents it: the format, whether the body and attachments are included, how you verify the request, and the size limits.

Published by
MarkRelay Research
Updated
Sources
7 primary sources, linked below

Summary

Every major sending service can also receive mail and POST it to your app, but the payloads differ. Resend's email.received webhook carries only metadata; you fetch the body and attachments from its API. Mailgun routes forward a parsed copy, form-encoded or JSON, with HMAC signature fields. SendGrid Inbound Parse posts multipart form data from a dedicated MX hostname, with an option for raw MIME and a recommended 30 MB ceiling, and documents no signature. Postmark posts JSON with the text, HTML, a stripped reply and base64 attachments up to 35 MB, and retries on failure. Cloudflare Email Workers give you the raw message and leave the rest to your code. MarkRelay posts a signed email.received event with the parsed message and attachment information to webhooks scoped to the mailboxes they cover, and keeps the message in your own Cloudflare account.

Key findings

  1. 1Resend: event email.received; the webhook has metadata only (IDs, from, to, subject, attachment list); body and attachments come from its API.
  2. 2Mailgun: route forward() POSTs body-plain, body-html, stripped text and attachments, as form data or JSON; signature, timestamp and token verify the request.
  3. 3SendGrid Inbound Parse: MX at a dedicated hostname to mx.sendgrid.net; multipart form data or raw MIME; keep messages under 30 MB; no request signature documented.
  4. 4Postmark: JSON POST with TextBody, HtmlBody, StrippedTextReply and base64 Attachments (35 MB total); 10 retries over up to 6 hours; inbound is listed on the Pro plan.
  5. 5Cloudflare Email Workers: the raw MIME stream in an email() handler; parsing, storage and any webhook are your code.

Questions this report answers

Asked by real people, quoted as they wrote them.

“email to webhook”

Google and Bing search suggestion

Point the domain's MX at a service that receives and posts each message to your URL: Mailgun routes, SendGrid Inbound Parse, Postmark inbound, Resend receiving, or a Cloudflare Email Worker. The table below shows what each one sends.

“Can I use GoDaddy email instead of EmailJS to receive emails via code?”

r/webhosting

Receiving in code needs mail delivered to something that calls your endpoint, which a hosted mailbox does not do by itself. Any of the services here can post each email to your code; MarkRelay does it from your own Cloudflare account and keeps a copy in a mailbox.

“how to receive email through laravel?”

Stack Overflow

Use an inbound webhook: the provider receives the mail and POSTs it to a Laravel route. Verify the request first: Mailgun with its HMAC signature, MarkRelay with HMAC-SHA256 over the timestamp and raw body.

“Is it possible to use email workers for notifications?”

r/CloudFlare

Email Workers can fetch() any URL with the message they receive, so they can notify a service. Parsing the MIME, retrying and signing are up to you.

What arrives at your endpoint

Resend

Format
JSON, email.received
Body and attachments in the request
No: metadata, then fetch via API
Verify the request
Not stated
Size
Not stated

Mailgun routes

Format
Form data or JSON
Body and attachments in the request
Yes, parsed; raw MIME option
Verify the request
HMAC signature, timestamp, token
Size
Not stated

SendGrid Inbound Parse

Format
multipart/form-data or raw MIME
Body and attachments in the request
Yes
Verify the request
None documented
Size
Keep under 30 MB

Postmark

Format
JSON
Body and attachments in the request
Yes, attachments base64
Verify the request
Not stated
Size
35 MB attachments

Cloudflare Email Worker

Format
Raw MIME stream in code
Body and attachments in the request
You parse it
Verify the request
Your code
Size
25 MiB inbound

MarkRelay

Format
JSON, email.received
Body and attachments in the request
Yes: content and attachment information
Verify the request
HMAC-SHA256 over timestamp and raw body
Size
25 MiB inbound (Cloudflare)

Not stated means the provider's own page does not say. Source: Resend receiving webhook, Mailgun receive via HTTP, SendGrid Inbound Parse, Postmark inbound, Cloudflare Email Workers.

Webhook only, or webhook plus a mailbox

The hosted services treat inbound mail as an event: they parse it, post it and, depending on the plan, keep it for a while. If the post fails past the retries, or you need to look at the original later, you depend on their retention.

MarkRelay stores every received message in the mailbox first, in your D1 database with attachments in R2, then posts the webhook. Each webhook is scoped to what its owner can access, one domain or chosen mailboxes, and every request carries X-MarkRelay-Event, a timestamp and an HMAC-SHA256 signature of the timestamp and raw body. The same mailbox is readable in the webmail and over the API, so a support agent or an AI agent can reply from it.

Where MarkRelay fits

A good fit when

  • Inbound mail that should land in a mailbox people can read, and in your app, at the same time.
  • Webhooks per mailbox or per domain with a signature you can verify, on Cloudflare.

Look elsewhere when

  • Inbound on a domain whose MX must stay with another provider.
  • Raw MIME posted to your endpoint: MarkRelay posts the parsed message.

Common questions

Does Resend's inbound webhook include the email body?

No. Resend's received-email webhook carries metadata only; you fetch the body, headers and attachments with its API.

How do I verify a MarkRelay webhook?

Compute HMAC-SHA256 with your signing secret over the X-MarkRelay-Timestamp value, a dot and the raw body, and compare it in constant time with X-MarkRelay-Signature.

Sources and method

  1. Resend receiving (resend.com/docs/dashboard/receiving/introduction)
  2. Resend receiving webhook (resend.com/docs/dashboard/receiving/create-receiving-webhook)
  3. Mailgun receive via HTTP (documentation.mailgun.com/docs/mailgun/user-manual/receive-forward-store/receive-http)
  4. SendGrid Inbound Parse (www.twilio.com/docs/sendgrid/for-developers/parsing-email/setting-up-the-inbound-parse-webhook)
  5. Postmark inbound (postmarkapp.com/developer/user-guide/inbound/parse-an-email)
  6. Postmark pricing (postmarkapp.com/pricing)
  7. Cloudflare Email Workers (developers.cloudflare.com/email-routing/email-workers/runtime-api/)

Facts are taken from each vendor's own pricing pages, documentation or terms as of the updated date above; prices are in US dollars per month unless stated. Cost comparisons apply each vendor's published rates to the same volume. MarkRelay is not affiliated with the providers covered here;MarkRelay sells a self-hosted email app, which this page mentions where it fits. Spotted something outdated? Tell us.

Revisions

  • : First published; every fact checked on the vendor's own pages.

Related guides

More research