Email Ingestion
Convert an inbound email to JSON and send it to the endpoint destinations.
Email ingestion converts an inbound email into a JSON relay payload. Send an email to the endpoint email address. PayloadRelay sends the payload to the configured destinations, with webhook, email, Slack, Discord, Microsoft Teams, PagerDuty, Telegram, and Google Sheets.
How email ingestion operates#
- Enable email ingestion on an endpoint.
- Save the endpoint. Copy the
emailIngestionAddressthat the API gives, above the configuration tabs. - When a sender sends an email to that address, PayloadRelay parses the email into a JSON payload.
- PayloadRelay examines the email, records the quota and the Activity metadata, and starts the delivery to the configured destinations.
- SMTP returns success after PayloadRelay accepts the email. If a temporary service problem occurs, PayloadRelay gives SMTP
451. The PayloadRelay mail server then keeps the email and sends it again later.
SMTP success means that PayloadRelay accepted the message. It does not mean that every downstream target delivered it. Activity can stay PENDING until all the delivery attempts end.
Email payload format#
PayloadRelay converts the inbound email into this JSON structure. The to list comes from the To: header of the message. It does not contain the ingestion address when the message arrives by BCC or through a forwarding alias.
{
"from": "[email protected]",
"fromName": "Example Sender",
"envelopeFrom": "[email protected]",
"to": ["[email protected]"],
"cc": ["[email protected]"],
"bcc": [],
"replyTo": "[email protected]",
"subject": "Order confirmation #1234",
"textBody": "Your order has been confirmed...",
"htmlBody": "<html>...</html>",
"date": "2024-01-15T10:30:00Z",
"messageId": "<[email protected]>",
"headers": {
"X-Mailer": "Outlook 16.0",
"X-Priority": "1"
},
"authResults": {
"spf": "pass",
"dkim": "pass",
"dmarc": "pass"
},
"authResultDetails": [
{
"authservId": "mx.example.net",
"method": "spf",
"result": "pass",
"properties": { "smtp.mailfrom": "[email protected]" }
}
]
}Included fields#
- The sender, the recipients (to, cc, bcc), and the reply-to address
- The subject line
- The text body content and the HTML body content
- The date and the message ID
- The selected email headers
Excluded content#
- PayloadRelay removes the attachments. It relays the text content only.
- The payload does not contain binary content, an inline image, or an embedded file.
Body-as-payload mode#
By default, the envelope JSON above is the relay payload. To use the plain-text body as the payload, enable Use the plain-text email body as the relay payload on the endpoint Details tab. For example, use this mode when an automated system sends a JSON document by email.
When this mode is enabled, PayloadRelay parses the body with the payload format of the endpoint:
| Payload format | Parsing |
|---|---|
JSON | PayloadRelay parses textBody as JSON. It rejects an HTML-only email. It does not use htmlBody as a fallback. |
XML | PayloadRelay forwards textBody as a raw XML text node. |
text/plain | PayloadRelay sends textBody as a string with no change. |
FORM, QUERY_PARAMS, QUERY_PARAMS_BASE64_JSON | PayloadRelay does not support these formats. It rejects the email as EMAIL_INGESTION_REJECTED. |
If the parsing fails, for example, when the body is not valid JSON for a JSON endpoint, PayloadRelay rejects the email with MALFORMED_JSON_PAYLOAD. The mail server of the sender receives an SMTP 550 permanent failure.
Filters and field validations#
When body-as-payload mode is enabled, the request body filters and the field validations in the Filter tab also apply to the parsed email body. You can make a field necessary or examine a field, as you do for an HTTP request. The Filter tab cannot remove a field. To remove a field, use a DELETE transform.
When body-as-payload mode is disabled, the filters and the field validations have no effect, because the metadata envelope has a fixed structure.
Use envelope fields as template variables#
When body-as-payload is enabled, the {{email.*}} namespace gives the envelope fields. These fields contain the sender, the subject, the recipients, and the headers. You can use them in a webhook custom body, a custom header, and an email subject or body. A template variable is a name that PayloadRelay replaces with a value. A dynamic Reply-To field for a primary email target can use a path such as email.replyTo or email.from.
{{email.from}}{{email.subject}}{{email.textBody}},{{email.htmlBody}}{{email.date}},{{email.messageId}},{{email.replyTo}}{{email.to}},{{email.cc}},{{email.bcc}}: PayloadRelay writes an array as a string with commas between the values.{{email.headers.X-Mailer}}, or a different header name
A header name in a variable is case-sensitive. It must match the header name in the email exactly. For example, {{email.headers.x-mailer}} does not find an X-Mailer header.
These variables are also available in envelope mode. A regular variable such as {{from}} and {{subject}} resolves against the payload.
The two modes give different values to the {{email.*}} variables:
- In envelope mode,
{{email}}and{{email.*}}show the payload after the transforms and the append-field rules. A masked field shows the mask. A removed field is absent. - In body-as-payload mode, the variables show the received email with no transform. The transforms change only the parsed body, so
{{email.textBody}}contains the original body. AMASKorDELETErule does not hide a value in it. If a transform hides a value in the body, do not put{{email.textBody}}in a template.
A failover email dynamic Reply-To field uses the failover payload. In envelope mode, use replyTo. In body-as-payload mode, use a manual Reply-To or a fallback Reply-To when the replies must go to the original sender.
Enabling email ingestion#
- Open the endpoint editor.
- In the header of the endpoint editor, select
Email ingestion endpointin theEndpoint typelist. - Save the changes.
- Open the saved endpoint and copy the email ingestion address that the API gives, above the configuration tabs.
The endpoint must be enabled and have the type Email ingestion endpoint to accept an inbound email. An endpoint has one type. A change from webhook to email clears the webhook configuration, with the inbound authentication, the captcha, the IP limits, the CORS, and the required headers.
Quota and billing#
Each new accepted inbound email consumes one accepted event from the monthly quota, in the same way as an accepted HTTP relay. A completed second delivery that PayloadRelay identifies as a duplicate consumes no quota, and it starts no new set of deliveries. An email relay payload also uses the plan size limit. The limit is 256 KB on Sandbox and Solo, 512 KB on the Team trial and Team, and 1 MB on Scale. For a custom plan, the agreement of the organization sets the limit.
Activity log#
An email-sourced relay appears in the Activity tab with these outcome types:
| Outcome | Meaning |
|---|---|
DELIVERY_QUEUE_UNAVAILABLE | A temporary service problem stopped the acceptance. The PayloadRelay mail server sends the email again later. The row contains metadata only. |
EMAIL_INGESTION_ACCEPTED | All the tracked deliveries ended with no error. The dashboard puts this outcome in Completed. It can appear as Pending while the deliveries continue. |
EMAIL_INGESTION_REJECTED | PayloadRelay rejected the email, because the ingestion is off, because PayloadRelay does not support the body-as-payload format, or because the body is empty or HTML-only where text/plain is necessary. If the endpoint has an allowed-senders list, PayloadRelay also discards a null-sender message and records this outcome. |
AUTH_FAILED | The SPF, DKIM, or DMARC enforcement failed, or an SMTP envelope sender that is not empty is not on the allowed-senders list. PayloadRelay discarded the email. |
REQUEST_BODY_FILTER_FAILED | The body-as-payload content did not agree with a request body filter. |
FIELD_VALIDATION_FAILED | The body-as-payload content did not agree with a field validation rule. |
MALFORMED_JSON_PAYLOAD | Body-as-payload mode needed JSON, but the email text body was not valid JSON. |
PAYLOAD_TOO_LARGE | The relay payload from the email is larger than the payload size limit of the plan, or the transform rules made it larger than this limit. |
SPF / DKIM / DMARC enforcement#
PayloadRelay can make a trusted SPF, DKIM, and DMARC result necessary before it accepts an inbound email.
Each endpoint has three independent controls in the Security tab: Require SPF pass, Require DKIM pass, and Require DMARC pass. They are off by default.
The enforcement fails closed. A rule passes only with a trusted pass. PayloadRelay discards mail with no result for the rule in the same way as mail with a failed result. Enable a control only when the senders use that authentication method.
The three rules do not bind the identity in the same way:
| Toggle | Identity binding |
|---|---|
Require SPF pass | Bound. The smtp.mailfrom identity must match the domain of the SMTP envelope sender. For a null sender, PayloadRelay accepts a pass that is tied to the reported smtp.helo identity. |
Require DKIM pass | Not bound. A trusted dkim=pass is sufficient with any signing domain (header.d). A forwarder, a mailing list, or an ESP can sign with its own domain. This proves that a system signed the message. It does not prove that the message came from the From domain. |
Require DMARC pass | Bound. The DMARC result must give header.from, and that value must match the header From domain. PayloadRelay does not accept a DMARC pass with no header.from. |
Use Require DMARC pass when the authentication must bind to the visible From address. Require DKIM pass alone does not prove the sender identity.
When the enforcement is enabled, PayloadRelay accepts a qualifying pass. If the result is missing, none, neutral, softfail, fail, or permerror, PayloadRelay discards the email and records AUTH_FAILED in Activity. The mail server of the sender receives SMTP 250, so PayloadRelay sends no bounce message to a sender address that an attacker can forge. If there is no qualifying pass and a trusted result is temperror, PayloadRelay gives SMTP 451. The PayloadRelay mail server then keeps the email and sends it again later.
| Header result | Enforcement outcome |
|---|---|
qualifying pass | PayloadRelay accepts the email. |
fail, softfail, permerror | PayloadRelay discards the email. |
none, neutral | PayloadRelay discards the email. |
temperror (with no qualifying pass) | PayloadRelay rejects the email temporarily with SMTP 451. The PayloadRelay mail server sends the email again later. |
| one rule in more than one trusted header | PayloadRelay discards the rule and uses it as a missing rule. PayloadRelay discards the email. |
| missing header | PayloadRelay discards the email. |
PayloadRelay also sends the compatibility authResults object in the email envelope payload, for example, {{email.authResults.spf}}. authResultDetails contains each trusted result and the identity properties for the enforcement. The SPF smtp.mailfrom value must match the SMTP envelope domain. The DMARC result must give a header.from value, and that value must match the header From domain.
In one Authentication-Results header, a qualifying pass wins. More than one DKIM signature is alternative evidence, and one valid signature is sufficient. In that header, temperror wins against the permanent non-pass results in the summary.
The same rule in two separate trusted headers has a different result. A boundary mail server reports each rule one time. A second occurrence means that one header or more did not come from that server. PayloadRelay cannot identify the genuine header. It discards the rule from authResults and authResultDetails. The rule then operates as a missing rule, and an endpoint that needs it discards the message.
The duplicate rule causes this result. The result values can be the same. A forged header that copies the genuine verdict and changes the identity can satisfy the identity binding, because SPF and DMARC accept a qualifying pass.
Trusted mail authentication results#
Use only trusted authentication results for the SPF, DKIM, and DMARC enforcement. If the organization uses custom mail routing, contact Support before you enable the enforcement. Support can make sure that the trusted results will be available.
SMTP envelope sender filter#
You can filter the SMTP envelope address with SMTP envelope sender filter in the Security tab.
- Add a specific address:
[email protected] - Use a wildcard for a pattern:
*@company.commatches a sender from that domain. - To permit every sender, leave the list empty. This is the default.
Each entry must be a valid email address, or a wildcard pattern of the same shape, such as *@company.com, billing@*, or *@*.example.com. You can add a maximum of 100 unique entries. Each entry can have a maximum of 320 characters. PayloadRelay changes the entries to lowercase when you save them. PayloadRelay rejects an invalid entry and a duplicate entry with 400 Bad Request, before it saves the endpoint. PayloadRelay does not accept a universal *@* pattern. Leave the list empty instead.
If a sender is not empty and is not on the permitted list, PayloadRelay discards the email and records AUTH_FAILED in Activity. The mail server of the sender receives SMTP 250, and PayloadRelay sends no bounce message. If the endpoint has an allowlist, PayloadRelay also discards a null-sender DSN or bounce. Activity records that message as EMAIL_INGESTION_REJECTED.
PayloadRelay applies this filter to the SMTP envelope sender (MAIL FROM), and not to the From: header of the message. This filter alone does not authenticate the sender, because a sender can state the local part of the SMTP mailbox. Enable the SPF enforcement when the envelope domain must bind to a trusted SPF pass. SPF authenticates the domain, and not the local part of the mailbox.
- PayloadRelay discards a message with
MAIL FROM:<[email protected]>and a forgedFrom: [email protected]header when[email protected]is on the allowlist. PayloadRelay examines[email protected]only. - A DSN bounce message uses the SMTP null sender (
MAIL FROM:<>). PayloadRelay discards it when the endpoint has an allowlist. To receive the bounces, leave the allowlist empty and use the SPF, DKIM, and DMARC enforcement.
DSN and bounce messages#
A Delivery Status Notification (DSN) and an automatic bounce message use the SMTP null sender MAIL FROM:<>. The examples are an out-of-office reply and a non-delivery report. RFC 5321 gives this sender. The SMTP envelope sender is an empty string.
With an allowlist: PayloadRelay discards a null-sender message, because the empty sender matches no pattern. To receive a bounce notification or a DSN notification, leave the allowlist empty.
With no allowlist: a null-sender message passes the sender rule. The envelopeFrom field is an empty string. The from field contains the value of the From: header, which can be the address of the bounce originator.
With the SPF enforcement: for a null sender, PayloadRelay accepts a trusted SPF pass that is tied to the reported smtp.helo identity. Some DSN messages contain no trusted result. Use a separate endpoint with no SPF enforcement when the DSN delivery must not depend on that result.
Email metadata headers injected into the payload#
PayloadRelay converts each relayed email into a structured JSON payload. The top-level fields are always present. Some values can be null or empty.
| Field | Source | Notes |
|---|---|---|
from | The bare mailbox in From: | A sender can forge this value. For a trust-sensitive test, use the structured authentication results. |
fromName | The name in From: | null when the header has no name. |
envelopeFrom | SMTP MAIL FROM | An empty string for a DSN or bounce null sender. Use this field for the allowed-sender enforcement. |
to | To: header | An array of addresses. |
cc | Cc: header | An array of addresses. An empty array when the header is absent. |
bcc | Bcc: header | Usually absent, because a delivered email does not normally contain this header. |
replyTo | The effective reply address | Uses the first Reply-To: mailbox when it is present. If it is not present, uses the first From: mailbox. It is null only when the message has neither. |
subject | Subject: header | An empty string when the header is absent. |
textBody | First text/plain MIME part | null when the message has no plain-text part. |
htmlBody | First text/html MIME part | null when the message has no HTML part. |
date | Date: header | An ISO 8601 UTC string, for example, 2024-01-15T10:30:00Z, or null. |
messageId | Message-ID: header | Contains the angle brackets, such as <[email protected]>. If the header is absent, PayloadRelay creates a value, and the field is not null. The value applies to one delivery, and it is not stable. A retry of the same message makes a different value. Do not use it to deduplicate. |
headers | All the other headers | A map from a header name to its first value. PayloadRelay removes the standard headers. See the list that follows. |
authResults | Authentication-Results: header | A map with the keys spf, dkim, and dmarc, and values such as pass and fail. |
authResultDetails | Trusted Authentication-Results: headers | An array of {authservId, method, result, properties}. null means that the detailed results are not available. An empty array means that the message reported no trusted result. |
The headers map#
PayloadRelay sends all the non-standard headers in the headers map. It removes these standard headers, because they are top-level fields:
From, To, Cc, Bcc, Reply-To, Subject, Date, Message-ID, Content-Type, Content-Transfer-Encoding, MIME-Version, and Authentication-Results
PayloadRelay also removes the reserved X-PayloadRelay-Loop loop-protection header.
The headers map can contain these headers, and more:
Received: the SMTP relay trace headers that each hop adds. When the message has more than one, the map keeps the first upstream occurrence only. PayloadRelay removes its own receiving hop. A message that comes directly to PayloadRelay with no earlier hop has noReceivedentry.DKIM-Signature: the raw DKIM signature from the sending domain.Return-Path: the bounce address when the sending infrastructure added one. This header is usually absent, because a final delivery agent normally adds it.ARC-*: the Authenticated Received Chain headers (RFC 8617).X-Mailer,X-Priority,X-Spam-Status, and the otherX-headers from the sender.List-Unsubscribe,List-Id, and the other RFC 2369 list headers.
The Received, DKIM-Signature, and ARC-* headers can contain routing details and infrastructure details. PayloadRelay can send them to the downstream targets. If this is not permitted, use a transform rule to remove them before the delivery.
The authResults map#
The authResults map contains the trusted results that came with the message. The keys are spf, dkim, and dmarc. The values are lowercase result strings: pass, fail, softfail, neutral, none, temperror, and permerror. A key is absent when the message reported no trusted result for that rule.
You can use these values in a template as {{email.authResults.spf}}, {{email.authResults.dkim}}, and {{email.authResults.dmarc}}.
authResultDetails keeps more than one SPF result or DKIM result. If a rule is in more than one trusted header, PayloadRelay removes every entry for that rule, and no entry can satisfy the enforcement. The related properties are smtp.mailfrom, smtp.helo, header.d, and header.from. PayloadRelay uses the authentication results for the enforcement only after it makes sure that they are trustworthy.
Limits and security boundaries#
- The inbound message size: the limit is approximately 2 MB. The front-end mail server accepts a maximum of 2,000,000 bytes. The receiver accepts a maximum of 2 MiB. PayloadRelay refuses a payload above the lower limit during the SMTP transaction. The attachments count against the limit, although PayloadRelay removes them.
- The plan payload limits also apply. The email envelope JSON must stay in the plan limit. In body-as-payload mode, the text body must stay in the same limit. The limit is 256 KB on Sandbox and Solo, 512 KB on the Team trial and Team, and 1 MB on Scale. For a custom plan, the agreement of the organization sets the limit.
- The attachments: the payload contains the text body and the HTML body only. See Multipart parsing.
- The SPF, DKIM, and DMARC enforcement uses the trusted authentication results in the email. When a necessary result is not available, PayloadRelay discards the message with the policy above.
- The webhook security features: the inbound authentication, the captcha, the required headers, the IP allowlists, and the CORS apply to an HTTP request. They are not available for an email endpoint. Use the allowed senders and the sender authentication enforcement.
- The transforms and the append-field rules apply to the JSON envelope or to the parsed body, before the delivery. They cannot copy a value from
textBodyorheadersto a different field. To use such a value in a destination, use a template variable, such as{{email.headers.X-Mailer}}.
Temporary payload handling#
PayloadRelay does not store a customer relay request body or a customer message body in its databases, activity logs, object storage, or backups. A body stays only in memory and in the delivery, retry, and dead-letter queues. It stays there only while PayloadRelay delivers the event. If the delivery fails permanently, the message stays in a dead-letter queue for a maximum of 7 days for diagnosis or a new delivery. PayloadRelay can keep operational metadata, such as an SMTP envelope sender address, in the 30-day Activity trail.
Delivery, retries, and deduplication#
Email ingestion and downstream delivery are at-least-once. PayloadRelay can identify a completed second delivery of an email, and prevent a quota charge and a new set of deliveries. A sender and a receiver must accept duplicates. After a temporary SMTP 451 result, the PayloadRelay mail server keeps the email in its queue and sends it again. It tries for a maximum of 5 days. After that time, it returns the email to the SMTP envelope sender.
The SMTP response tells the mail server of the sender if a new attempt is useful:
| SMTP result | Typical conditions |
|---|---|
250 | New accepted mail, or a completed duplicate that PayloadRelay identifies. The downstream delivery can still be pending. PayloadRelay also gives 250 when it discards an email because of the SPF, DKIM, or DMARC enforcement, the SMTP envelope sender filter, or a content rule of the endpoint. Activity records the discarded email. |
451 | A pause or maintenance, an authentication temperror, a rate limit or a quota limit, a billing block, or a different temporary service problem. The PayloadRelay mail server sends the email again for a maximum of 5 days. |
550 | An unknown, disabled, or wrong-type recipient, usually rejected at RCPT TO, a malformed email, a body that is empty, not valid JSON, or HTML-only where text/plain is necessary, or disabled email ingestion. |
452 at RCPT TO | The SMTP transaction attempted a second valid relay recipient. The first recipient stays accepted. |
Send one PayloadRelay relay recipient in each SMTP transaction.
The content rules of the endpoint are the request body filters, the field validation rules, the payload size limit of the plan, and the body-as-payload format. If a content rule rejects an email, PayloadRelay discards the email and sends no bounce message. An attacker can forge the SMTP envelope sender, so a bounce message can go to a person who did not send the email. Activity records the outcome, for example REQUEST_BODY_FILTER_FAILED or PAYLOAD_TOO_LARGE.
Email relay loop protection#
An email from a direct PayloadRelay email destination, an email failover, or a webhook response-forward email carries the reserved X-PayloadRelay-Loop header. PayloadRelay permits a maximum of three relay hops. One hop count covers email and HTTP, so a chain such as email to an HTTP endpoint to email stops at the same limit. At the limit, PayloadRelay does not send the email. It marks the delivery as failed with a reason in the delivery log. A webhook destination, a chat destination, and the other destinations that are not email continue. PayloadRelay removes the reserved header from the payload metadata that a user sees. The loop protection needs no customer configuration.
Multipart parsing#
PayloadRelay extracts the email bodies from the MIME structure with these rules:
| Part type | Extraction behavior |
|---|---|
text/plain | PayloadRelay extracts it as textBody. When the message has more than one text/plain part, PayloadRelay uses the first part. |
text/html | PayloadRelay extracts it as htmlBody. When the message has more than one text/html part, PayloadRelay uses the first part. |
Attachments (a different content type, Content-Disposition: attachment, or binary) | PayloadRelay removes them. PayloadRelay relays the text content only. |
| Inline images or embedded files | PayloadRelay removes them. |
Deeply nested messages and attachments#
PayloadRelay can ignore a MIME part with very deep nesting. It removes the attachments, and it does not cut them. The message must stay in the PayloadRelay email size limit.
Use cases#
- Alert forwarding: send a system alert email to Slack, Discord, or a webhook.
- Form submissions by email: accept a structured email and send it to a webhook or a Google Sheet.
- An email-to-API bridge: convert a third-party email notification into an API call through a webhook target.
- Monitoring dashboards: send the email alerts to one central webhook endpoint.