Email Rate Limiting for Safe, Predictable Sending

Email rate limiting is admission control for your sending pipeline. It decides when a message may enter the next stage, based on the narrowest current limit for the account, connection, API key, recipient domain, or traffic class.
The safe pattern is to queue first, admit work at a measured rate, and slow down when a provider returns pressure signals. Transactional mail needs reserved capacity so a campaign cannot delay password resets or security alerts.
Treat every limit as a separate counter
An email system rarely has one universal limit. The provider may count API requests, messages, recipients, concurrent SMTP connections, or accepted volume across a longer window. Your plan and account history can also change which ceiling applies.
| Limit | What it controls | What to record |
|---|---|---|
| Request rate | HTTP calls made with a key or account | Status, reset signal, request ID |
| Message rate | Submitted messages in a short window | Account, stream, accepted time |
| Recipient rate | Total recipients, including batches | Recipient count per accepted message |
| SMTP concurrency | Open or active submission sessions | Connection count and reply code |
| Account quota | Provider-specific second, minute, hour, or day allowance | Used, remaining, and reset time |
| Message size | Encoded body and attachments | Final encoded bytes, not source file size |
Do not combine these into a single messages-per-second setting. A request carrying many recipients can fit under a request limit while crossing a recipient limit. Several application instances can each appear safe while exceeding one shared account quota together.
Put a queue in front of every sending route
A queue absorbs bursts without turning them into simultaneous provider calls. The limiter should run when work leaves the queue, not when your application first creates the message.
Classify each message before enqueueing it. A useful starting split is authentication and security, other transactional mail, product notifications, and bulk traffic. Give each class an explicit priority and a maximum queue age.
Reserve some provider capacity for the urgent classes. If bulk work can consume the full allowance, priority labels alone will not protect a password reset that arrives after the limit is exhausted.
Choose the counter shape that matches the rule you are enforcing. A token bucket permits a controlled burst while maintaining an average rate. A rolling window is useful when the provider measures activity across a moving period. A concurrency limit needs a semaphore rather than a time bucket.
Handle HTTP and SMTP pressure differently
HTTP 429 Too Many Requests means the client exceeded a rate limit. RFC 6585 allows the response to include Retry-After, but does not require it. When the header is present, wait for that period before retrying the affected scope.
If no reset signal is available, apply a bounded exponential backoff with random jitter. Reduce admission for the account or key that was limited. A global stop is appropriate only when the evidence shows the limit is global.
SMTP uses reply classes instead of HTTP status codes. RFC 5321 defines 4yz replies as transient failures that may succeed when repeated later. It defines 5yz replies as permanent failures that should not be repeated unchanged.
Store the complete SMTP reply, enhanced status code when present, account, recipient domain, and attempt count. Do not reduce every 421, 450, or 451 response to the same generic throttle label. The text and enhanced code help distinguish capacity pressure from mailbox or policy problems.
Retry the logical message, not a new message
Retries need a stable identity. Without one, a network timeout can leave the client unsure whether the provider accepted the first attempt, and a second request can produce a duplicate email.
For an HTTP sending API that supports idempotency, attach one key to the logical send and reuse that key with the same request body. Keep the key stable across timeout and rate-limit retries. A changed payload is a new operation and needs a new identity.
Give each queued message a retry budget. Track attempt count, first-attempt time, next-attempt time, and the last provider response. Expire work when it can no longer meet its product purpose instead of retrying forever.
Add jitter to scheduled retries. If a worker fleet receives the same reset time and wakes at one instant, it can recreate the burst that caused the limit.
Keep transactional and bulk traffic independent
Separate queues are the first boundary. Separate provider scopes or account groups provide a stronger boundary because one stream cannot consume another stream's assigned route by accident.
Use distinct sending identities when their reputation and timing requirements differ. Bulk traffic can usually wait for capacity. Authentication messages often lose value within minutes and need a much shorter queue-age alert.
Test the boundary with three cases: no capacity, one available slot, and a burst larger than the current allowance. Confirm that urgent mail progresses when bulk mail is queued, and that resuming a paused queue does not release everything at once.
Measure queue health, not just send volume
The most useful warning is often the age of the oldest queued message. Queue depth can look acceptable while one small, high-priority stream is stuck behind repeated deferrals.
Track admission rate, queue age by class, provider responses, retry outcomes, and recipient-domain deferrals. Separate accepted, delivered, bounced, and expired states. An accepted API request proves that the provider took responsibility for the message, not that the recipient received it.
Alert on changes from the normal baseline for each route. A rising retry ratio or older transactional queue can identify pressure before a hard limit blocks new work.
Where Sendmux fits
Sendmux lets teams set per-second, per-minute, per-hour, and per-day quotas on their custom SMTP sending accounts. Delivery groups can keep a sending key or mailbox on a selected set of accounts, which helps separate product, customer, region, or risk-based traffic.
The Sendmux Sending API marks rate-limit errors as retryable and returns Retry-After on its 429 responses. Its idempotency header lets a client safely retry the same logical send with the same body.
These controls do not replace application priorities or expiry rules. Keep your own queue policy close to the product flow, then use account quotas and delivery groups as the provider boundary.
Sources
Frequently Asked Questions
What is an email rate limit?
An email rate limit caps requests, messages, recipients, connections, or accepted volume within a defined window. The counter and scope matter: a limit may apply to one API key, sending account, tenant, connection, recipient domain, or traffic class.
How do you solve an "email rate limit exceeded" error?
Identify which counter and scope were limited, queue the same logical message, and reduce admission for that scope. Honour Retry-After when it is present, use bounded backoff with jitter when it is absent, and reuse the same idempotency key and body for an API retry.
How many emails can you send in 24 hours?
There is no universal daily number. Providers may count requests, messages, or recipients, and may use a calendar reset or a rolling window. Check the current limit for the exact account, plan, route, and sending method, then set your application limiter below the proven available capacity.
How do you bypass an email size limit?
Do not try to bypass it. Reduce the final encoded message size, compress suitable files, or send a secure download link for large content. Check the sending API and receiving provider limits because attachment encoding makes the transmitted message larger than the source files.