Limits and retention
Every product limit from the core limits table, where each kind applies, and how long content, metadata and logs are kept.
Where limits apply
- Request validation. Sizes and counts on a request (recipients, subject length, attachments, tags, headers, batch size, idempotency key length) are checked before anything is stored and fail with
422 validation_errorand anissueslist, or400 invalid_idempotency_key. - Rate limits. Each key has a per-second request limit, counted in one-second windows and reported in
ratelimit-limit,ratelimit-remainingandratelimit-reset; past it, requests answer429 rate_limit_exceededwithretry-after. A key's ownrate_limit_per_secondstays within the project's ceiling (API keys). - Daily cap. Live mail is capped per project per UTC day. The cap counts the live emails the project accepted since midnight UTC, suppressed ones included; past it, sends answer
429 daily_quota_exceededuntil the next day. Owners and admins raise it in the project's settings. - Sending pauses. A project whose bounce or complaint rate climbs too high stops sending live mail until an owner or admin resumes it. Alerts warn first, and the thresholds are in the console (When sending pauses).
- Retention. Content (bodies, attachments, raw inbound mail) is purged after the content retention period, subjects and custom headers with it; metadata, events and runs after the metadata retention period; request logs after theirs. Daily counts and the consent ledger are kept.
The keys are the names the platform gives each limit. Byte values are in KB and MB, fractions in percent.
The table
| Limit | Value | Description |
|---|---|---|
recipientsPerEmail | 50 | to, cc and bcc together on one email. |
recipientsPerField | 50 | |
subjectMax | 998 | |
messageBytesMax | 40 MB | Whole MIME message after encoding, SES v2's maximum. Also what one request (a batch included) may download for remote path attachments in total. |
htmlBytesMarketingMax | 100 KB | Gmail clips HTML above about 102 KB; marketing is blocked above this, transactional warned. |
htmlBytesWarn | 100 KB | |
attachmentsPerEmail | 20 | |
trackedLinksPerEmail | 500 | Links rewritten for click tracking per email, in document order; later links stay untracked. |
attachmentBytesMax | 25 MB | Stored attachments (uploaded through a presigned URL). |
inlineAttachmentBytesMax | 4 MB | Base64 inside a JSON request body, which stops at 6 MB. |
inlineImportBytesMax | 4 MB | |
requestBodyBytesMax | 6 MB | |
uploadUrlTtlSeconds | 900 seconds | Presigned upload URLs for attachments and imports. |
attachmentFilenameMax | 255 | |
storedAttachmentTtlDays | 30 days | Stored (reusable) attachments are purged after this many days without use. |
tagsPerEmail | 50 | Caller tags are stored and returned in events; only the platform's own tags go to SES. |
tagLengthMax | 256 | |
customHeadersMax | 50 | |
headerNameMax | 128 | |
headerValueMax | 2,000 | |
headersBytesMax | 8 KB | |
batchSize | 100 | |
idempotencyKeyMax | 256 | |
idempotencyWindowHours | 24 hours | |
scheduleMaxDaysAhead | 30 days | |
templateVariablesMax | 100 | |
templateVariableKeyMax | 64 | |
templateHtmlBytesMax | 1 MB | |
templateNameMax | 100 | |
templateAliasMax | 100 | A template's alias: lowercase letters, digits, hyphens and underscores. |
templateVersionsKept | 50 | |
documentBlocksMax | 200 | The block document (hosted templates and broadcasts): blocks in a document and in one of its columns, the document's width, and the sizes a block may set, all in pixels. |
columnBlocksMax | 20 | |
documentWidthMin | 320 | |
documentWidthMax | 800 | |
imageWidthMin | 16 | |
imageWidthMax | 1,200 | |
spacerHeightMin | 4 | |
spacerHeightMax | 200 | |
blockPaddingMax | 80 | |
apiRateLimitPerSecondDefault | 10 | Per API key: requests per one-second window, hard limit (no separate burst allowance). |
apiRateLimitPerSecondMax | 100 | Ceiling a project may configure for any of its keys. |
linksRateLimitPerMinute | 120 | Recipient pages (links.): requests per minute per client address. |
dailySendCapDefault | 10,000 | Per project per UTC day, live mode. Raised per project in settings. |
contentRetentionDays | 30 days | Content (bodies, attachments, raw inbound) in S3. |
metadataRetentionDays | 395 days | Emails, events, received messages, finished runs, DMARC reports and the audit log: 13 months, so year-over-year reports work. |
apiRequestLogRetentionDays | 30 days | |
presignedUrlTtlSeconds | 3,600 seconds | |
outboundRedirectsMax | 3 | Redirects followed by outbound requests to caller-supplied URLs; each target is re-checked. |
outboundResponseBytesMax | 64 KB | Response bytes kept from outbound requests (webhook responses are stored truncated). |
remoteAttachmentTimeoutMs | 15,000 ms | Remote attachment downloads (path attachments): one deadline for every download of a request, a batch included, so the request ends well inside the API function's 30 seconds. |
webhookEndpointsPerEnvironment | 20 | |
webhookDescriptionMax | 200 | A webhook endpoint's description, as its owner writes it. |
webhookTimeoutMs | 15,000 ms | |
webhookRetryDays | 3 days | |
webhookMaxAttempts | 20 | |
webhookRetryDelaysSeconds | 5 seconds, 300 seconds, 1,800 seconds, 7,200 seconds, 18,000 seconds, 36,000 seconds | The wait before each retry of a failed delivery, in seconds: after the first failure, the second, and so on; the last repeats until webhookRetryDays from the delivery's creation (12 attempts in all) or webhookMaxAttempts. |
webhookAutoDisableDays | 3 days | Consecutive days of only failures before an endpoint is disabled automatically. |
webhookToleranceSeconds | 300 seconds | Signature timestamp tolerance, matching svix. |
webhookInboundContentBytesMax | 256 KB | Parsed inbound content carried inside the email.received webhook. |
inboundMessageBytesMax | 40 MB | SES receiving refuses larger messages. |
inboundAttachmentsMax | 100 | Attachments kept per received message; the rest are dropped and the message says so. |
inboundHeaderBytesMax | 256 KB | Header bytes across every part of a received message (a line counts for at least 64). |
inboundMimePartsMax | 1,000 | MIME parts in a received message, nested messages included. |
inboundMimeDepthMax | 32 | Multipart nesting depth of a received message. |
inboundNestedMessagesDepthMax | 3 | Attached messages (message/rfc822) parsed inline; deeper ones stay attachments. |
inboundAddressesMax | 1,000 | Addresses read from From, To, Cc and Bcc, nested messages included; each list keeps at most recipientsPerField. |
inboundDataUriBytesMax | 2 MB | Inline images embedded as data URIs in html (html_format=data_uri); larger ones stay cid:. |
inboundForwardHopsMax | 3 | Platform forwarding hops (counted from X-Minket-Forwarded headers) before a loop is assumed. |
inboundRoutesPerDomain | 100 | Routing rules per receiving domain. |
inboundLocalPartMax | 64 | The local part a routing rule matches, the part before the @ (RFC 5321's limit). |
inboundForwardAddressesPerProject | 50 | Forwarding destinations per project (each confirmed by its owner). |
inboundForwardConfirmTtlHours | 72 hours | A forwarding confirmation request waits this long for its owner's reply. |
dmarcReportBytesMax | 1 MB | DMARC aggregate reports: the attachment as received, and after decompression. |
dmarcReportDecompressedBytesMax | 10 MB | |
dmarcReportAttachmentsMax | 3 | Report attachments read from one message. |
dmarcXmlElementsMax | 200,000 | XML elements and nesting depth in one report; <record> rows read from it. |
dmarcXmlDepthMax | 16 | |
dmarcReportRecordsMax | 10,000 | |
dmarcReportSourcesKept | 200 | Sending sources kept per stored report, largest counts first. |
headerRetentionDays | 30 days | Subjects and custom headers are cleared with the content; addresses stay for the metadata period. |
pageSizeDefault | 20 | |
pageSizeMax | 100 | |
metricsPeriodsMax | 10,000 | Email metrics: periods one range may span with period as a dimension. |
metricsFilterIdsMax | 100 | Email metrics: ids per domain_id, email_id or broadcast_id filter. |
metricsRowsMax | 10,000 | Email metrics: rows one breakdown may answer; past it, shorten the range or filter. |
orgNameMax | 32 | Organization names, so a name fits one line of the console's switcher. |
projectNameMax | 32 | |
slugMax | 50 | |
keyNameMax | 100 | |
automationNameMax | 200 | Automation names; a duplicate is named <name> (copy), cut to fit. |
broadcastNameMax | 200 | Broadcast names; a duplicate is named <name> (copy), cut to fit. |
domainNameMax | 253 | |
domainsPerProject | 50 | |
environmentsPerProject | 5 | |
membersPerOrg | 50 | |
invitationTtlDays | 14 days | An invitation is accepted on the invitee's first sign-in within this many days. |
contactsPerProject | 1,000,000 | |
importRowsMax | 100,000 | |
importFileBytesMax | 50 MB | |
importColumnsMax | 100 | CSV imports: columns per row and characters per field; longer rows or fields fail the file. |
importFieldMax | 1,000 | |
importRowErrorsMax | 100 | Per-row errors kept on an import (the counts include every failed row). |
exportRowsMax | 200,000 | Contacts in one synchronous CSV export; filter by segment or status for larger audiences. |
propertiesPerProject | 100 | |
propertyKeyMax | 50 | |
propertyValueMax | 1,000 | |
segmentRulesMax | 50 | |
segmentNameMax | 100 | Segment names: shown whole in the console's segment register and as a broadcast's audience. |
topicsPerProject | 50 | |
topicNameMax | 100 | Topic names, and the name the preference page shows in their place (public_name). |
topicDescriptionMax | 500 | A topic's description, under its name on the preference page. |
sunsetAfterDays | 365 days | Contacts with no open or click in this many days are sunset (left out of broadcasts). |
sunsetAfterDaysMin | 30 days | The range a project may configure for its sunset period. |
sunsetAfterDaysMax | 730 days | |
doubleOptInTtlHours | 72 hours | |
broadcastThrottlePerMinuteDefault | 600 | Each broadcast sends at most its throttle_per_minute, this by default; every broadcast from one domain draws on that domain's per-minute budget. |
broadcastSesRateShare | 50% | The share of the sending rate broadcasts may use, so transactional mail always has room. |
broadcastAbSamplePercentMax | 50% | |
broadcastAbWindowMinutesMax | 1,440 minutes | |
broadcastTestRecipientsMax | 5 | |
automationStepsMax | 100 | |
automationWaitMaxDays | 90 days | |
automationRunsPerContactPerDay | 50 | One contact enters one automation at most this often per day (runaway guard). |
automationVersionsKept | 50 | |
automationRunStepsMax | 500 | Steps one run may execute; a run past it fails (runaway guard: loops through waits). |
automationChainDepthMax | 3 | Runs started by events of another automation's run, at most this deep (loop guard). |
automationEventPayloadBytesMax | 16 KB | A custom event's payload as stored with the runs it starts (JSON bytes). |
eventDefinitionsPerProject | 200 | Custom event definitions per project. |
eventSchemaFieldsMax | 50 | Fields in one custom event definition's schema. |
dnsCheckIntervalMinutes | 60 minutes | How often a domain that is not verified yet is checked again. |
dnsCheckVerifiedIntervalMinutes | 360 minutes | How often a verified domain is checked again. |
dnsRecordPendingHours | 72 hours | A missing record stays pending this long after the domain was added, then failed (SES's own window). |
integrationTimeoutMs | 10,000 ms | Calls to the Cloudflare API, Google Postmaster Tools, seed IMAP servers, OAuth token endpoints, and the test login before an SMTP or IMAP mailbox is saved. |
cloudflareZonesMax | 500 | Zones read from one Cloudflare connection. |
domainConnectTimeoutMs | 5,000 ms | Each Domain Connect request to a DNS provider (its settings, whether it has a template): the domain page waits for them, so they give up sooner than other integrations. |
domainConnectCacheSeconds | 300 seconds | What a zone's Domain Connect discovery found is reused this long (per function). |
smtpCredentialsPerOrg | 20 | SMTP credentials an organization can hold at once. |
smtpCredentialNameMax | 100 | An SMTP credential's name, the client it is for ("Supabase auth"). |
seedTestIntervalDays | 7 days | Scheduled inbox-placement tests run this often per verified domain. |
seedCheckDelayMinutes | 10 minutes | Placement is read this long after the seed messages were sent. |
seedCheckGiveUpHours | 24 hours | A seed message not found by then is recorded as missing. |
eventsFeedLagSeconds | 5 seconds | Events younger than this are left out of the GET /v1/events feed so a tail never skips a late commit. |
recipientTokenTtlDays | 400 days | Signed recipient-page tokens (unsubscribe, preferences) stay valid this long. |
emailShareHoursMax | 48 hours | A shared email's link lasts this long at most, and by default. |
sessionDays | 30 days | Sign-in and accounts. Sessions last sessionDays absolutely and sessionIdleDays without use; email codes are six digits valid signInCodeMinutes. |
sessionIdleDays | 14 days | |
signInCodeMinutes | 10 minutes | |
signInCodeAttemptsMax | 5 | |
signInCodesPerEmailPer15Minutes | 3 minutes | |
signInStartsPerAddressPerHour | 20 | |
organizationsPerUserMax | 3 | Organizations one person may own through sign-up (platform administrators are exempt). |
sandboxDailyQuotaDefault | 100 | |
sandboxMonthlyQuotaDefault | 3,000 | |
quotaMax | 10,000,000 | The highest daily or monthly quota an organization may be given. |
mailboxesPerProject | 50 | Connected mailboxes (Gmail, Microsoft, SMTP) per project. |
oauthStateTtlSeconds | 600 seconds | An OAuth connect flow must come back within this many seconds; its state is single use. |
oauthClientIdMax | 500 | A project's own OAuth client, its id and its secret as the provider issued them. |
oauthClientSecretMax | 1,000 | |
mailboxSendTimeoutMs | 15,000 ms | One request or SMTP session of a mailbox send, connection included (the Sent copy over IMAP has its own). A token refresh and the one retry after a 401 still fit the send worker's one-minute timeout; a send cut short there stays in flight and is never repeated. |
gmailMessageBytesMax | 25 MB | What Gmail sends in one message (its upload endpoint takes 35 MB; delivery stops at 25). |
graphMessageBytesMax | 3 MB | Microsoft Graph takes 4 MB per sendMail request, so about 3 MB of MIME before base64. |
mailServerResponseBytesMax | 64 KB | Bytes read from an SMTP or IMAP server in one session (replies only, never mail). |