Comparisons · September 21, 2026
Evaluate Agent Email Provider Security Without SOC 2
Twelve questions that judge an agent email provider's security from its public API reference in ten minutes, plus the cases where a SOC 2 report still wins.
Procurement asks one question about the email provider your agent will use: where is the SOC 2 report. The vendor has one or it does not, and the evaluation usually stops there. That question cannot tell apart a provider whose agent credential is scoped to a single inbox from one where the agent carries the same token your billing job carries, because no audit report is written at that resolution. The standard advice on how to evaluate agent email providers security says to verify certifications, and every vendor worth shortlisting will pass that check with the same answer.
Twelve questions follow. Each one has an artifact for an answer: an endpoint, a scope string, a key prefix, an HTTP response code. Each is checkable against a vendor’s public API reference in about ten minutes, with no NDA and no call. There is also a table for deciding when the audit report is genuinely the better evidence, because sometimes it is. If what you want is the mechanics of scoping credentials rather than a way to assess a vendor that ships them, read permission scopes for agent email instead. The head-to-head evaluations live on the comparisons hub.
What a SOC 2 report proves, and what it cannot reach
A SOC 2 Type II report proves that an auditor sampled a set of controls over a window and found them operating as described. That is real evidence, and it is evidence about things an API reference genuinely cannot show you: whether leavers get deprovisioned, whether changes go through review, whether backups are restored and not merely taken. If your risk is that the vendor’s own staff mishandle your mail, an audit report is better information than anything in this article, and you should weight it accordingly.
What the report cannot reach is the shape of the authority you are about to hand an autonomous program. Three structural reasons:
- The vendor picks the scope. SOC 2 is not a fixed control list. The service organisation selects which criteria and which systems are in scope, so “we have a report” and “the thing you are buying was examined” are separate claims.
- The report is usually behind an NDA. You cannot compare two vendors on a document you have to sign for, you cannot show it to the engineers who will own the integration, and you cannot check either copy against the running product.
- It is written about a company, not about a token. No Trust Services criterion says whether a credential can be restricted to one mailbox, or whether an agent’s tool list shrinks when its grant does. Those are product decisions, and they are either in the API reference or they do not exist.
So the two bodies of evidence answer different questions, and which one decides your purchase depends on what you are actually afraid of:
| What you are actually worried about | The evidence that settles it | Why the other evidence does not |
|---|---|---|
| Vendor staff reading your mail store | The audit report | No API reference describes who inside the vendor holds production access. |
| Regulated data you may not process without an attestation | The audit report | A shipped control is not the artifact your regulator or insurer asked for. |
| A board, customer or insurer with a checkbox | The audit report | The checkbox is the requirement. Controls are not what is being counted. |
| An agent sending something it should not have sent | The twelve questions | No criterion is written about the blast radius of a token you mint yourself. |
| A leaked agent key | The twelve questions | A report says keys are rotated, not that a key can be bound to one mailbox. |
| Proving to your own engineers that the blast radius is small | The twelve questions | They cannot read the report, and it would not answer them if they could. |
| Two shortlisted vendors that both hold the same certification | The twelve questions | Identical evidence cannot discriminate. This is the common case. |
The recommendation flips in one place worth naming. If a vendor holds a report but the scope statement covers a different system than the product you are buying, the report is weaker evidence than a published API reference, not stronger. Read the scope section before you accept the badge. The reverse flip is simpler: no quantity of shipped control substitutes for an attestation you are contractually obliged to collect.
Run both evaluations. The twelve below are the half most buyers skip, because nobody sends them as a form.
How to evaluate agent email provider security: twelve questions
Every row is answerable from documentation the vendor already publishes. The third column is what the answer sounds like when the control is absent and the sales engineer is being agreeable rather than precise.
| # | Question | Artifact that answers it | A weak answer |
|---|---|---|---|
| 1 | Can a credential be bound to one mailbox, not the whole account? | The key-creation request body accepts a list of inbox IDs. | “You can create separate accounts.” |
| 2 | Is composing a message a different permission from sending one? | Two distinct scope strings exist. | “Use read-only if you are worried.” |
| 3 | Does the agent’s tool list shrink when its grant does? | The tool list returned for a reduced grant omits the send tool. | “The call is rejected if it lacks the scope.” |
| 4 | Can a credential be minted with more authority than its creator? | A documented error at creation time, not at use time. | “Admins should be careful.” |
| 5 | Is authority read from the token, or recomputed per request? | Documented behaviour when the authorising human loses access. | “Tokens expire after 24 hours.” |
| 6 | Can a test credential reach a real recipient? | Environment encoded in the key prefix, with no override flag. | “Use the sandbox header.” |
| 7 | Does the approval gate hold the message, or only log it? | A send response that returns no message ID at all. | “Approvals are in the audit log.” |
| 8 | Does an approval bind to a message version or to an agent? | A version number on the draft and an invalidation event. | “Approved agents can send freely.” |
| 9 | Is every action retrievable as an ordered, replayable record? | An events endpoint with a monotonic sequence cursor. | “We have logs. Ask support.” |
| 10 | Is a retried send idempotent by construction? | An idempotency header the endpoint requires rather than accepts. | “Do not retry.” |
| 11 | Can you export your data and have it erased, self-serve? | Export and deletion endpoints in the reference. | “Open a ticket.” |
| 12 | Does the vendor publish what it does not do? | A page listing absent certifications and absent guarantees. | Silence. |
Questions 3, 5, 6 and 7 are the ones that separate vendors. The rest are table stakes that plenty of providers still fail. The sections below work through them against this product, so you can see what a checkable answer looks like before you go and demand one from somebody else.
Three further checks are worth running even though they appear on nobody’s questionnaire, because each has a one-line answer and each is expensive to retrofit:
- Does another tenant’s object ID return not-found or forbidden? A 403 confirms the object exists, which turns any ID-shaped field into an existence oracle. Here another tenant’s IDs return the same not-found as an ID that was never issued.
- Can a webhook be pointed at an internal address? Your agent’s event endpoint is a URL you supply, which makes it a server-side request forgery primitive if nobody is checking. On this system a separate service resolves the address, pins the connection to a public IP, verifies TLS, and refuses redirects and private networks.
- Does a language model sit anywhere in the mail path? Core mail here does not invoke one. Permissions, approvals, policy and webhook dispatch are ordinary application code and SQL, so no inbound text is ever interpreted by the component that decides whether a send is allowed.
Can a credential be smaller than the account that created it
Yes, on two axes at once: a named set of scopes, and a named set of inboxes.
curl -X POST "https://api.emailforagents.ai/v1/projects/$EFA_PROJECT_ID/keys" \
-H "Authorization: Bearer $EFA_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "support triage (draft only)",
"scopes": ["inboxes:read","threads:read","messages:read","drafts:write","drafts:submit"],
"inbox_ids": ["ibx_..."]
}'
Two things in that body answer questions 1 and 2. The inbox_ids array is the mailbox
boundary: the credential resolves to those inboxes and returns not-found for everything
else in the workspace. And drafts:submit is a different string from messages:send,
which is the whole of question 2. A credential holding the first and not the second can
compose a complete, addressed, formatted message and has no route by which that message
leaves the building.
Question 4 is answered at creation time rather than at use time. Requesting a scope
your own role does not hold fails immediately with permission_denied. You cannot
mint a key more powerful than yourself and discover it later. That ordering matters for
an evaluation, because a system that checks at use time has a window in which an
over-privileged credential exists and is sitting in someone’s environment file.
The full scope vocabulary is published, which is itself part of the answer. Read it
against a vendor’s list: if theirs contains a single mail or full_access scope, rows
1 and 2 are already failed regardless of what the trust page says.
Does the tool surface shrink, or does the vendor deny the call afterwards
This is question 3 and it is the one almost nobody asks. The common industry answer is an allowlist: the model decides to call a send tool, the request goes out, and a policy layer rejects it. That works, and it leaves the capability visible in the agent’s context the entire time. Everything an attacker needs is still on the menu, and the model can be argued into trying, repeatedly, in ways your logs have to absorb.
The alternative is to make the capability absent. Six MCP tools exist in total:
list_inboxes, list_threads, list_messages, get_message, create_draft and
send_message. An OAuth connection granted read and draft authority gets an MCP session
whose tools/list contains the first five. send_message is not present. The model
is not refused; it never sees that sending is a thing it could attempt, so there is no
instruction hidden in an inbound email that can talk it into the attempt.
{
"tools": [
{ "name": "list_inboxes" },
{ "name": "list_threads" },
{ "name": "list_messages" },
{ "name": "get_message" },
{ "name": "create_draft" }
]
}
create_draft cannot transmit mail. That is a property of the tool, not of the prompt
wrapped around it.
Here is the part an evaluation should push on, because a vendor with only half of this
will describe it as though they have all of it. A reduced tool surface and a call-time
permission check act at different moments, and you want both. The tool list is filtered
by the grant at the moment tools/list is answered, which protects the model’s context.
The authority check runs when a call arrives, which protects the mailbox. Both exist
here: a tools/call for a tool outside the grant is rejected with permission_denied
and the message “This connection cannot use that tool”, even though the model should
never have seen the name to try it.
That pairing matters because of a gap nobody writes down. The server advertises no tool-list-changed capability, so narrowing a grant does not push a new tool list to a client that is already connected. A long-lived session keeps showing the model the menu it was handed at connect time; what actually stops the send is the call-time check, and the tool only disappears from the model’s context when the session reconnects. So when you reduce an agent’s authority, treat reconnecting the client as part of the change, not as housekeeping. A provider with only the tool-surface control leaves open sessions holding capability it can still attempt. A provider with only the call-time check leaves the capability advertised forever. Ask which they have, and ask specifically what happens to an open session when a grant is reduced.
Worth checking on any provider that offers both protocols: an API key is rejected at
https://mcp.emailforagents.ai/mcp by design. Only an OAuth connection grant may call
MCP tools, so a leaked server key does not quietly become an agent session. The
trade-offs between the two paths are set out in
MCP or REST for agent email.
Be clear about the limit of this control, because a vendor that is not clear about it is selling you something. A reduced tool surface removes one class of attack: the agent cannot be argued into an action whose tool is missing. It does nothing about injected content inside a draft that a human then approves. That failure mode, and the ones next to it, are in prompt injection through an agent’s inbox.
Does the approval gate hold the message, or only record it
Question 7 distinguishes a gate from a notification. The test is simple: send through the gate and look at what comes back.
curl -X POST \
"https://api.emailforagents.ai/v1/projects/$EFA_PROJECT_ID/inboxes/$EFA_INBOX_ID/messages" \
-H "Authorization: Bearer $EFA_AGENT_KEY" \
-H "Idempotency-Key: eval-probe-001" \
-H "Content-Type: application/json" \
-d '{
"to": [{"email":"you@example.com"}],
"subject": "Approval gate probe",
"text": "This should not leave the building."
}'
{
"result": "approval_required",
"draft_id": "drf_...",
"draft_version": 1,
"approval_id": "apr_...",
"reason_codes": ["draft_only_principal"]
}
There is no message_id in that response, because no message exists. Nothing was handed
to a provider and then recalled. reason_codes says which rule fired:
draft_only_principal when the credential itself cannot send, or always,
new_recipient_domain or attachments when the inbox policy demands review. A vendor
whose equivalent response carries a message ID and a pending_review flag has built a
notification, not a gate, and the difference shows up the first time their review queue
is slow.
draft_version is question 8. The approval binds to that version of that message, to
those recipients, with that body: the canonical payload is hashed with SHA-256 and the
digest stored on both the approval and the draft version, so a decision that no longer
matches what the reviewer read is refused at approval time with version_conflict
rather than sent. Approving is not the
same as trusting the agent, which is the confusion the whole
approval queue is built to prevent. The reviewer ergonomics, the
three sending postures and the cases where approvals do not help are covered in
human approval for agent email.
Is authority recomputed on each request, or frozen into the token
Question 5 is the one whose answer most vendors have never written down, which is informative in itself.
A bearer token usually carries a claim set. The service reads the claims, trusts them until expiry, and revocation means waiting out a cache. Here the token is a lookup handle rather than a claim set: effective permission is recomputed from current database state on every request, and intersected with the current grant of the human who authorised the credential. Take that person off the project and every key they minted narrows on the next call. No revocation step, no cached-token window, no fifteen-minute gap in which a former employee’s agent is still sending.
For an evaluation, the question to ask is not “can I revoke a key”, because every vendor says yes. Ask what happens to a key when the human who created it loses access, and ask where that is documented. A vendor whose answer is “the key keeps working until you revoke it separately” has told you that agent credentials sit outside their joiner and leaver process, which is precisely the gap a SOC 2 report about the corporate directory will not surface.
The same recomputation is why nothing written in an inbound email can widen a grant. Text cannot edit the database rows that authority is derived from. It can still persuade an agent to compose something regrettable within the authority it already has, which is why the gate in the previous section is not optional.
Can a test credential ever reach a real recipient
No, and the reason is structural rather than procedural, which is what question 6 is really probing.
Environment is carried in the key prefix. A secret is efa_live_ or efa_test_, then
eight hex characters, then a 43-character body, returned once. An efa_test_ key
resolves only to test projects and test inboxes. There is no header, flag or parameter
that lets it cross, and a project’s environment is fixed at creation.
Test inboxes go further: they are issued non-routable .mail.invalid addresses behind a
simulated transport, so a test project is incapable of putting mail on the internet even
if every other check failed at once. The limits are published too: up to three active
test inboxes per workspace, the last 100 messages retained, up to 10 MB, content expiring
after seven days, and test mail never charged as an email unit.
This is the row where most sandbox-shaped answers fall down in an interesting way. Ask the vendor whether their test mode can deliver mail into your agent, not just intercept what your agent tries to send. The distinction is easy to miss because both are called a sandbox, and it decides what your test suite is capable of proving. Outbound capture shows your send code is wired correctly. It cannot exercise receive, parse, thread and reply, which is where an agent inbox actually lives and where its bugs actually are. A vendor whose sandbox is outbound-only has handed you a test suite that stays green while the inbound half of the agent is broken.
What we do not hold, said plainly
An evaluation-criteria article written by a vendor is worth nothing unless the vendor answers its own question 12 first. So:
- We hold no SOC 2, ISO 27001, HIPAA or GDPR certification of any kind.
- No independent security review has been commissioned for public launch.
- We publish no uptime SLA, no uptime percentage and no incident-response commitment.
- There is no end-to-end data-residency promise and no bug bounty programme.
- Custom domains require a paid plan, and paid plans are not purchasable yet. Live mail
is received and sent on
agents.emailforagents.ai. - Provider acceptance is not proof of delivery, and no inbox placement is promised.
Most of that list is on the security page rather than buried, because absence is easy to misread as an oversight. If your risk assessment requires an audit report, we do not clear it today and you should choose a vendor that does; the table in the first section says as much. What we will not do is describe controls we have not shipped in language that sounds like an attestation.
Questions 9 and 11 round out the set and are quick to check anywhere. An events endpoint
with a monotonic per-project sequence cursor gives you an ordered, replayable record
rather than a log you have to request, and /v1/projects/{project_id}/exports makes
export an API call rather than a ticket. Read the deletion answer more carefully, ours
included: /v1/deletion-jobs is self-serve, but in this build it deactivates rather than
erases. It stops routing, revokes keys and connections, and returns data_erased: false
with physical_purge_blocked: true. Permanent erasure still needs a manual request and
review, as the data controls page says. Question
10 is the Idempotency-Key header, which sends require rather than merely tolerate; a
header the endpoint accepts when offered is not the same control as one it refuses to
proceed without, because the second cannot be forgotten by the caller.
Running the questionnaire in ten minutes
Open the vendor’s API reference, not their trust centre, and do this in order:
- Find the key or token creation endpoint. Does the request body take a list of mailbox identifiers, and a list of scopes? Rows 1 and 2.
- Count the scope strings. One scope for mail is a fail; separate draft and send scopes are a pass. Still row 2, and it is the fastest disqualifier on the list.
- Search the reference for what happens when you request a scope you do not hold. An error at creation is a pass; silence means it is checked at use time, if at all. Row 4.
- Find the tool list returned to a connected agent. Is it fixed, or does it vary with the grant? Ask what happens to an open session when the grant narrows. Row 3.
- Search for what happens when the authorising user is removed. If it is not written down, ask in writing. Row 5.
- Find the test or sandbox section. Can it receive, or only intercept? Row 6.
- Read the send endpoint’s response schema. Is there a branch that returns no message identifier? Row 7, plus row 8 if a version number appears anywhere near an approval.
- Search for an events endpoint with a cursor, an idempotency header, and export and deletion endpoints. Rows 9 to 11.
- Search their site for the words “we do not”. Row 12, and the most informative search of the nine.
Anything still unanswered after that is a question for the call, and it is now a specific question with a specific artifact attached rather than a form. Take the list to the comparisons hub and run it against whichever provider you are weighing this one against, including us.
Keep reading
Scoped Credentials for Agent Email: Read, Draft, Send
Give an agent the smallest useful email permission: project and inbox scoping, one-time secrets, draft-only grants, rotation, and revocation you can verify.
Human Approval Before an AI Agent Sends Email
When to require review, why approval binds to one exact draft version, how recipient rules and daily caps work, and what editing a draft does to its approval.
Prompt Injection by Email: What Actually Helps
Any stranger can email your agent. What an email-borne injection looks like, why message text must never grant permission, and the controls that limit damage.