Webhook Payload

Inbound emails POST to your endpoint as application/json with this schema. A Primitive-Signature header carries the HMAC-SHA256 signature; see Signature verification. The high-level primitive.receive(...) SDK helper exposes a normalized ReceivedEmail shape if you don't want the raw event envelope.

EmailReceivedEvent* = required
FieldTypeDescription
idreqstringUnique delivery event ID.
eventreq"email.received"Event type identifier. Always `"email.received"` for this event type.
versionreqWebhookVersionAPI version in date format (YYYY-MM-DD). Use this to detect version mismatches between webhook and SDK.
deliveryreqobjectMetadata about this webhook delivery.
endpoint_idreqstringID of the webhook endpoint receiving this event. Matches the endpoint ID from your Primitive dashboard.
attemptreqintegerDelivery attempt number, starting at 1. Increments with each retry if previous attempts failed.
attempted_atreqstringISO 8601 timestamp (UTC) when this delivery was attempted.
emailreqobjectThe email that triggered this event.
idreqstringUnique email ID in Primitive. Use this ID when calling Primitive APIs to reference this email.
received_atreqstringISO 8601 timestamp (UTC) when Primitive received the email.
smtpreqobjectSMTP envelope information. This is the "real" sender/recipient info from the SMTP transaction, which may differ from the headers (e.g., BCC recipients).
helostring | nullHELO/EHLO hostname from the sending server. Null if not provided during SMTP transaction.
mail_fromreqstringSMTP envelope sender (MAIL FROM command). This is the bounce address, which may differ from the From header.
rcpt_toreqstring[]SMTP envelope recipients (RCPT TO commands). All addresses that received this email in a single delivery.
headersreqobjectParsed email headers. These are extracted from the email content, not the SMTP envelope.
message_idstring | nullMessage-ID header value. Null if the email had no Message-ID header.
subjectstring | nullSubject header value. Null if the email had no Subject header.
fromreqstringFrom header value. May include display name: `"John Doe" <[email protected]>`
toreqstringTo header value. May include multiple addresses or display names.
datestring | nullDate header value as it appeared in the email. Null if the email had no Date header.
contentreqobjectRaw email content and download information.
rawreqRawContentRaw email in RFC 5322 format. May be inline (base64) or download-only depending on size.
downloadreqobjectDownload information for the raw email. Always present, even if raw content is inline.
parsedreqParsedDataParsed email content (body text, HTML, attachments). Check `status` to determine if parsing succeeded.
ParsedDataCompleteobjectParsed email content when parsing succeeded.
ParsedDataFailedobjectParsed email content when parsing failed.
analysisreqEmailAnalysisEmail analysis and classification results.
spamassassinobjectSpamAssassin analysis results.
forwardForwardAnalysisForward detection and analysis results.
authreqEmailAuthEmail authentication results (SPF, DKIM, DMARC).
spfreqSpfResultSPF verification result.
dmarcreqDmarcResultDMARC verification result.
dmarcPolicyDmarcPolicyDMARC policy from the sender's DNS record.
dmarcFromDomainstring | nullThe organizational domain used for DMARC lookups.
dmarcSpfAlignedreqbooleanWhether SPF aligned with the From: domain for DMARC purposes.
dmarcDkimAlignedreqbooleanWhether DKIM aligned with the From: domain for DMARC purposes.
dmarcSpfStrictboolean | nullWhether DMARC SPF alignment mode is strict.
dmarcDkimStrictboolean | nullWhether DMARC DKIM alignment mode is strict.
dkimSignaturesreqDkimSignature[]All DKIM signatures found in the email with their verification results.

Notes

Delivery & retries

delivery.attempt is the attempt number (1 to 6). The event id (evt_ + 64 hex chars) stays stable across retries; track it for idempotency and return 2xx for events you've already processed. Full retry schedule on the Receiving mail page.

Raw email content

The raw email is included inline (base64-encoded) if it's smaller than 256KB. For larger emails, raw.included will be false and you'll need to fetch it from download.url.

Attachments

Attachment metadata is always included in the payload. To download the actual files, fetch the attachments_download_url which returns a tar.gz archive. Each file in the archive is named according to its tar_path.

Parsing failures

If email parsing fails, parsed.status will be "failed" and parsed.error will contain details. You can still access the raw email content to parse it yourself.

HTML safety

parsed.body_html contains the raw parsed HTML body. Treat it as untrusted content and sanitize it before rendering in a browser.

Spam analysis

The analysis.spamassassin.score field contains the SpamAssassin spam score. Higher scores indicate higher likelihood of spam. Typical thresholds are 5+ for spam. You decide how to handle it. We never silently drop mail.

Authentication results

auth includes the SPF and DMARC verdicts, alignment booleans, and an array of DKIM signatures (with domain, selector, key bits, and algorithm). Use these for your own anti-spoofing logic on top of Primitive's.

Forward detection

analysis.forward flags messages that contain a forwarded email (inline or as an attachment) and surfaces the original sender along with DKIM verdicts on that inner mail. Useful for detecting forwarded-as-attachment fraud or building “reply to the real sender” workflows.

Threading

parsed.in_reply_to and parsed.references carry the RFC 5322 threading headers when present. The high-level client.reply() helper uses these to chain replies correctly without your having to set them by hand.