Email status
Ruuster's verdict on each lead's email address (valid, invalid, blocked, soft bounce, complaint, unsubscribed, unknown), how to read it, how to get it by lookup or webhook, and how to keep it in Follow Up Boss, Sure Send or Sierra Interactive through their APIs.
Ruuster checks a lead's address before the first email it sends them, and records what happens on every send after that: bounces, blocks and drops from the mail provider, unsubscribes and spam reports. This guide explains the one verdict Ruuster makes from that history and the two ways to get it: a lookup, and a webhook event when it changes.
- Look it up: Get a lead's email status, by email, CRM id or lead id.
- Be told when it changes: the
lead.email_status_changedwebhook event. - Keep it in your CRM: write it to custom fields (or tags) through your CRM's API on each event, so smart lists and action plans can use it. See Keep it in your CRM.
The statuses
status |
Means | What to do |
|---|---|---|
valid |
Ruuster is delivering to this address | Nothing |
invalid |
The mailbox does not exist, is closed or disabled, is a throwaway address or a spam trap, or the address is on the bounce list | Call or text instead, or get a new address |
blocked |
The recipient's mail provider refused the message for policy, reputation or content reasons. The mailbox itself may be fine | Use another channel for now |
soft_bounce |
A temporary problem: the mailbox is full, or their server did not answer | The address may still be good. Keep it |
complaint |
The lead reported a Ruuster email as spam, so sends to them are dropped | Do not email them from Ruuster again |
unsubscribed |
The lead unsubscribed from Ruuster emails, or the CRM record carries an opt-out tag | Respect it. If they ask to receive emails again, email helpme@ruuster.com |
unknown |
Not verified yet, or the check could not decide | Normal for new leads; see below |
Precedence when more than one thing is true: delivery on is always valid; the lead's own
unsubscribe outranks a later bounce; a recorded failure outranks a CRM opt-out tag.
Why new leads are unknown. Ruuster verifies an address right before the first email it
sends, not when the lead arrives. A lead who has not been emailed yet has not been checked yet.
About six in ten of a brokerage's newest contacts are in this state; it resolves on the first send.
What comes with the status
| Field | Description |
|---|---|
code |
What is behind the verdict: the SMTP code and whether it was a bounce or a block (5.1.1 bounce, 4.2.2 block), the verification status (inbox_full, disposable), or the suppression reason (unsubscribed address, spam reporting address). null when valid |
reason |
One sentence, in plain words |
source |
platform (the delivery flags), verification (the pre-send check), delivery (a send), lead (they unsubscribed), crm (an opt-out tag) |
checkedEmail |
The address the verdict is about, when lead contact details are on. Compare it with the lead's current email to tell whether a changed address has been checked yet |
failedAt |
When the failure behind the verdict was recorded, if there is one |
since |
When the verdict last changed |
previousStatus |
The verdict before this one, when known |
Look up one lead
curl -s "https://api.ruuster.com/v1/leads/email-status?email=sam.lee%40example.com" \
-H "x-api-key: $RUUSTER_API_KEY" -H "x-email: $RUUSTER_EMAIL"
The answer lists every lead with that address (a person can be a registered user and a CRM
contact), each with emailStatus. The verdict is refreshed every 15 minutes; a lead the refresh
has not reached yet, or whose address changed since, is classified on the call and comes back
with since and previousStatus null. It is a lookup call: 20 per minute per key.
In an AI assistant the tool is leads_email_status: "what's the email status for sam.lee@example.com".
Be told when it changes
Subscribe to lead.email_status_changed, or to lead.*, which includes it. It fires when the
verdict moves: a check or a send fails, the lead unsubscribes, delivery is turned back on, or a new
lead's address gets its first verdict. data.emailStatus carries the fields above plus
previousStatus; data.lead names the lead and its crmExternalId. A brokerage's first fill
publishes no events; only changes after that do.
{ "kind": "lead.email_status_changed", "occurredAt": "2026-10-29T14:10:00Z",
"data": { "lead": { "leadId": "user:c0ff3e21-8a4b-4c7d-9e15-2b6f8d3a1c04", "firstName": "Sam", "lastName": "Lee", "crmExternalId": "48213", "agentId": "7c1e9b42-3d85-4a6f-9e07-1b2c8d4f5a69" },
"emailStatus": { "status": "invalid", "code": "5.1.1 bounce",
"reason": "The mailbox does not exist or no longer accepts mail.",
"source": "delivery", "failedAt": "2026-10-29T14:02:11Z",
"since": "2026-10-29T14:10:00Z", "previousStatus": "valid" } } }
See Webhooks for subscribing and Verifying deliveries for signatures.
Keep it in your CRM
Ruuster posts a "Ruuster Email Validation" note on the CRM contact when it validates an address,
but notes cannot be filtered. With the webhook and your CRM's own API you can keep the verdict
where lists and action plans can use it: custom fields in Follow Up Boss and Sure Send, tags in
Sierra Interactive (its API has no custom fields). data.lead.crmExternalId is the person's id in
your CRM.
What to store, from each event:
| Store | From | Follow Up Boss | Sure Send | Sierra Interactive |
|---|---|---|---|---|
| Status | data.emailStatus.status |
customRuusterEmailStatus (dropdown) |
custom field, dropdown | tag Ruuster Email: invalid (one of seven) |
| Status code | data.emailStatus.code |
customRuusterEmailStatusCode (text) |
custom field, text | a note, if wanted |
| Validated email | data.lead.email (lead contact details on) |
customRuusterValidatedEmail (text) |
custom field, text | a note, if wanted |
| Validation date | data.emailStatus.failedAt, else since, as YYYY-MM-DD |
customRuusterValidationDate (date) |
custom field, date | a note, if wanted |
Answer each delivery with a 2xx within 10 seconds, then make the CRM call. Deliveries are at least
once, so de-duplicate on the event id if a repeat would matter. A PUT on a person in all three
CRMs leaves every field you don't send untouched.
Follow Up Boss. Create the four fields once: through POST /v1/customFields with an owner key
(label, type of dropdown, text or date, and choices for the dropdown), or under Admin,
then Custom Fields. The name in each field (customRuusterEmailStatus and so on) is the key you
write. Then on each event:
curl -s -X PUT -u "$FUB_API_KEY:" -H "Content-Type: application/json" \
"https://api.followupboss.com/v1/people/$CRM_EXTERNAL_ID" \
-d '{"customRuusterEmailStatus":"invalid","customRuusterEmailStatusCode":"5.1.1 bounce",
"customRuusterValidatedEmail":"sam.lee@example.com","customRuusterValidationDate":"2026-10-29"}'
Sure Send. Create the four fields once through POST /customFields (or in Settings) and note
the keys it gives them; a custom-field key that doesn't exist is dropped silently, so create them
first. Then on each event, with the keys from your account:
curl -s -X PUT -H "Authorization: Bearer $SURESEND_API_KEY" -H "Content-Type: application/json" \
"https://api.suresend.ai/api/partner/people/$CRM_EXTERNAL_ID" \
-d '{"customFields":{"ruusterEmailStatus":"invalid","ruusterEmailStatusCode":"5.1.1 bounce",
"ruusterValidatedEmail":"sam.lee@example.com","ruusterValidationDate":"2026-10-29"}}'
Sierra Interactive. The API has no custom fields, so use one tag per status. tags adds and
removeTags removes, so send the new tag and remove the other six in the same call; the code and
date can go in a note (POST /leads/{id}/note) if you want them on the record:
curl -s -X PUT -H "Sierra-ApiKey: $SIERRA_API_KEY" -H "Content-Type: application/json" \
"https://api.sierrainteractivedev.com/leads/$CRM_EXTERNAL_ID" \
-d '{"tags":["Ruuster Email: invalid"],
"removeTags":["Ruuster Email: valid","Ruuster Email: blocked","Ruuster Email: soft_bounce",
"Ruuster Email: complaint","Ruuster Email: unsubscribed","Ruuster Email: unknown"]}'
Fill in existing contacts. The event covers changes from now on. For contacts you want filled
today, call Get a lead's email status with each
one's crmExternalId and make the same write. It is a lookup call, 20 per minute per key, so
start with the contacts you email.
Then, for example: a smart list where the status is invalid or complaint and a phone is set is
your "call instead" list; soft_bounce stays in email plans; unsubscribed stays out of them;
and a contact whose email no longer equals the validated email has a new address Ruuster has not
checked yet. Ruuster re-validates it on its own once it syncs, and the next event updates the
fields.
Good to know
- Ruuster never emails an invalid, complaint or unsubscribed address. The status tells you what Ruuster already stopped doing.
- Resubscribing a lead. When a lead who unsubscribed asks to receive emails again, email support at helpme@ruuster.com with the lead's name and address and we turn delivery back on; the status returns to
validand the change fires an event. - A repeat of the same failure is not a change. A second full-mailbox bounce leaves
sincealone and sends no event. A different code, a different status or a changed address does. - One verdict per address. Two CRM contacts with the same email get the same status.
- A fixed address. When the email is corrected in your CRM, the new address syncs to Ruuster within minutes and is checked before the next send. Until then
checkedEmailstill shows the old one. - Contact details off. The lookup and the event still work;
checkedEmail,emailandphoneare left out.