Skip to content

Chaos and faults

Real mail servers fail. Fault rules make simmail’s SMTP server fail on purpose, so you can test that your app retries, backs off and reports bounces properly.

Faults apply to mail your app sends over SMTP. Mail sent with POST /api/send is not affected. Changing them needs the admin role.

A rule says when to misbehave and how.

FieldMeaning
nameYour label.
kinderror (the default), greylist, rate or drop.
stageWhen in the SMTP conversation: mail, rcpt or data.
matchWhich addresses: an exact address, @domain, or empty (or *) for all.
rateChance, 0 to 1, that an error or drop rule fires.
codeThe SMTP reply code, such as 421, 450, 451, 452, 550, 552 or 554. 0 means delay only.
enhancedThe enhanced status code, such as 5.7.26. Defaults to the code’s class (5.0.0).
messageThe reply text your app sees.
delay_msWait this long before answering.
retry_afterGreylisting: seconds before a retry is accepted.
per_minuteRate limiting: messages a minute before deferring.
windowOnly at certain times (below).
enabledWhether the rule is on.
Stagematch is compared with
mailThe sender (MAIL FROM).
rcptEach recipient (RCPT TO).
dataEach recipient, then the sender, once the message has been sent.
KindBehaviour
errorWith chance rate: waits delay_ms, then answers code. With code 0 it only delays.
greylistThe first attempt for each sender and recipient pair is deferred with 451 4.7.1; a retry after retry_after seconds is accepted.
rateMore than per_minute messages in a minute are deferred with 421 4.7.0.
dropWith chance rate: waits delay_ms, then closes the connection without answering.

code, enhanced and message override the defaults for greylist and rate too.

The first enabled rule that matches, is in its window, and fires decides. Greylisting and rate rules that let a message through hand over to the next rule. Order your rules from most to least specific.

PUT /api/faults replaces the whole list:

Terminal window
curl -s -X PUT https://c1.simmail.dev/api/faults \
-H "Authorization: Bearer smk_your_admin_key" \
-H "Content-Type: application/json" \
-d '[
{ "name": "Harbor mailbox is full", "stage": "rcpt", "match": "dana@harbor.test",
"rate": 1, "code": 552, "enhanced": "5.2.2", "message": "Mailbox full", "enabled": true },
{ "name": "Flaky server", "stage": "data", "rate": 0.2, "code": 451,
"message": "Temporary local problem, try again", "enabled": true }
]'

GET /api/faults reads them. PUT /api/faults with [] clears them.

Scenarios are ready-made rules with the codes and wording big providers really send. GET /api/faults/scenarios lists them. POST /api/faults/scenarios/{id} adds one as an enabled rule:

Terminal window
curl -s -X POST https://c1.simmail.dev/api/faults/scenarios/gmail-rate \
-H "Authorization: Bearer smk_your_admin_key" \
-H "Content-Type: application/json" \
-d '{"match": "@gmail.com"}'

The body is optional: a non-empty match replaces the scenario’s match, and window limits it in time. The answer is the full list of rules.

IdProviderWhat happens
gmail-unauthenticatedGmail550 5.7.26 at data for @gmail.com: unauthenticated sender.
gmail-rateGmailRate limit of 10 a minute for @gmail.com, 421 4.7.28.
gmail-no-userGmail10% of @gmail.com recipients do not exist, 550 5.1.1.
gmail-over-quotaGmail10% of @gmail.com recipients are over quota, 452 4.2.2.
microsoft-busyMicrosoft30% of @outlook.com recipients deferred, 451 4.7.500 “Server busy”.
microsoft-blockedMicrosoft550 5.7.1 blocklisted client host, at the mail stage for @outlook.com.
microsoft-access-deniedMicrosoft@outlook.com recipients refused, 550 5.4.1.
yahoo-deferredYahoo / AOLHalf of sessions deferred, 421 4.7.0 [TSS04], at the mail stage for @yahoo.com.
yahoo-policyYahoo / AOL554 5.7.9 at data for @yahoo.com: not accepted for policy reasons.
greylistingAny serverGreylisting, retry accepted after 60 seconds.
rate-limitAny serverMore than 20 messages a minute deferred with 421.
dropAny server20% of messages: the server hangs up during data.
slowAny serverEvery message takes 20 seconds to be accepted.
mailbox-fullAny server10% of recipients have a full mailbox, 552 5.2.2.

A window limits a rule to certain times on the universe’s simulated clock, such as “Thursdays from 14:00 to 15:00”:

{ "days": "thu", "from": "14:00", "to": "15:00", "tz": "Europe/London" }
FieldValues
daysmon, mon-fri, sat,sun, all (also * or empty)
from, toHH:MM. A window may run past midnight, such as 22:00 to 02:00.
tzA time zone name. Defaults to the server’s.

Simple refusals and delays are in every plan. Greylisting, rate limits, dropped connections, windows and scenarios need the chaos profiles feature of your plan; without it, the API answers 402.

Faults change the SMTP conversation. To have an address accept mail and then bounce it later, as many real providers do, use the recipient rules instead: mark an address full, unknown, disabled, blocked or domain, or make a share of never-seen addresses dead.