Skip to content
Groundmail

A real email address for your agent in one API call.

Groundmail gives your agent a mailbox it creates itself: it receives mail, searches it, waits for the next message and replies in the thread. Sign-in codes and links come back as their own fields.

Three mailboxes free on every plan. Inbound is free. No card to sign up.

One call, and the address works.

Leave out the domain and the mailbox lands on agents.groundmailbox.com, with no DNS to set up. Mail sent to it is kept, threaded and searchable.

  • local_part is the part before the @. Leave it out and we generate one
  • external_id is your own id, usable anywhere you name the mailbox
  • A +tag reaches the same mailbox, so one agent can use a different address per service
  • display_name, retention_days and spam_threshold are set per mailbox
  • The same from the SDK, the CLI and create_mailbox on the MCP server
Create a mailbox
curl -X POST https://api.groundmail.dev/mailboxes \
  -H "Authorization: Bearer $GROUNDMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "local_part": "signup-bot",
    "external_id": "agent-42"
  }'
201 Created
{
  "mailbox": {
    "id": "mbx_3f9c2a1b7d8e4f6a0b1c2d3e",
    "address": "signup-bot@agents.groundmailbox.com",
    "hosted": true,
    "status": "active"
  }
}
Or from the CLI
groundmail mailboxes create --local-part signup-bot

Wait for the next message, or get a webhook.

Your agent doesn't have to poll. wait holds the call open until matching mail lands, then returns it. For many mailboxes, a signed webhook fires on each new message.

  • GET /mailboxes/{id}/wait waits up to 60 seconds, and the SDK keeps going for longer
  • since catches mail that landed before you started waiting
  • mailbox.message.received carries the sender, subject, code and links
  • q searches the subject, sender and visible text
  • Replies group into threads, with labels, read state and archive
Node SDK
import { Groundmail } from 'groundmail'

const groundmail = new Groundmail(process.env.GROUNDMAIL_API_KEY!)

const mailbox = await groundmail.mailboxes.create({
  local_part: 'signup-bot',
})

const since = new Date()
await page.fill('#email', mailbox.address)
await page.click('text=Sign up')

const message = await groundmail.mailboxes.wait(mailbox.id, {
  since,
  timeout: 60_000,
})
await page.fill('#code', message.code!)
POST /webhooks
{
  "url": "https://acme.com/hooks/mail",
  "events": ["mailbox.message.received"],
  "mailboxes": ["signup-bot@agents.groundmailbox.com"]
}

The code is a field, and so are the links.

Sign-up mail comes back ready to use. Your agent reads the one-time code and the links straight from the message, with no parsing of its own.

code
The one-time code, 4 to 8 digits, or null when there is none
links
The links a reader can see, in order, with no duplicates. We never fetch them
visible_text
What a person would see, with hidden text left out
reply_text
The same, without quoted history
GET /mailboxes/{id}/messages/{message_id}
{
  "object": "mailbox_message",
  "from": "no-reply@acme.com",
  "subject": "Your code",
  "code": "482913",
  "links": ["https://acme.com/verify?t=1"],
  "sender_verified": true,
  "spam_status": "clean",
  "prompt_injection": { "flagged": false, "signals": [] },
  "visible_text": "Your code is 482913",
  "untrusted": true
}

Reply in the thread, and email people first from your own subdomain.

Threading is built for you. Start on a hosted address with no DNS. Add your own subdomain when your agent needs to write first.

Hosted address

Addresses on agents.groundmailbox.com work with no DNS. They can reply to a sender who passed DMARC. They can't email anyone first.

Your own subdomain

Addresses on agents.acme.com can reply and email people first, inside new-recipient limits.

New-recipient limits

A new recipient is someone the tenant, or your account, has never written to.

Free
3 an hour, 5 a day and 10 a week
Paid plans
10 a day in week 1, 25 a day in week 2, then 50 a day
Replies
A reply to a sender who passed DMARC doesn't count
First contact
Always carries one-click unsubscribe
CLI
# Reply in the thread
groundmail mailboxes reply bot@agents.acme.com mbm_3f9c2a1b \
  --text "Thanks, that worked."

# Email someone first
groundmail mailboxes send bot@agents.acme.com \
  --to ada@example.com \
  --subject "Your report" --text "It is ready."
Not allowed

Cold outreach isn't allowed on mailboxes.

Sales language, unfilled merge fields or the same message to more than 3 people in a day are refused. Too many complaints or bounces pause the mailbox, and receiving never stops.

Agent mail runs on its own stream, kept separate from your transactional mail, with its own bounce and complaint tracking.

Every message is untrusted, and says so.

Anyone who knows the address can write to your agent. So received mail carries untrusted: true and four checks that tell your agent how careful to be. None of them makes a message safe.

sender_verified

The From domain is proved by aligned SPF or DKIM. We check the message as received and ignore its own headers.

spam_score

Every message gets a score and a status. Spam is held back from your agent, and you set the threshold.

visible_text

What a person would see. Hidden HTML and invisible characters are left out, so they can't reach your agent this way.

prompt_injection

A flag, with the patterns that matched. It's a hint: a message with no flag is just as untrusted.

Give each agent its own key, limited to its mailboxes with mailbox_ids, so a fooled agent can't reach anything else in your account.

Agents for your customers, each on their own tenant.

Tenants are optional. If your platform runs agents for your own customers, pass tenant when you create a mailbox and each customer stays apart from the rest.

  • New-recipient limits count per tenant
  • Too many complaints or bounces pause the mailbox first, then that tenant, before the rest of your account
  • mailbox_ids limits an API key to the mailboxes you name
  • mailboxes on a webhook endpoint sends each customer only their own mail
  • Tenants come with pay as you go, with no per-tenant fee

Three mailboxes free, then $1 a month each.

Inbound is free. Sends count as emails on your plan, the same as any other send. See pricing.

  • Free stops at 3 mailboxes. A fourth needs pay as you go, $15 a month with 20,000 emails included
  • Extra mailboxes are prorated when you add or delete one
  • Paid plans can keep mail from 1 to 365 days
  • No card to sign up. Sending to other people on Free needs a card on file, never charged
3
Mailboxes included on every plan
$1
A month for each extra mailbox on a paid plan
$0
For receiving mail
90 days
Mail kept on paid plans by default, 7 days on Free

Questions

Can my agent email people first?

Yes, from your own subdomain. A mailbox on your subdomain can email someone first, inside the new-recipient limits, and first contact always carries one-click unsubscribe. A hosted address on agents.groundmailbox.com can only reply, and only to a sender who passed DMARC.

Do I need to set up DNS?

Not for a hosted address. For your own, add a subdomain such as agents.acme.com and publish its records. A main domain is refused, because its MX record would take over all of its mail.

What happens to mail sent to an address I didn't create?

It's dropped: there are no catch-alls. A +tag reaches the same mailbox, so signup-bot+acme@agents.groundmailbox.com lands in signup-bot with plus_tag on the message.

Can someone else get a hosted address after I delete it?

No. A hosted address is never given out again, so a new owner can't receive your agent's password resets.

Can I move a hosted address to my own subdomain?

Yes. Forward it to a mailbox on your subdomain and its mail keeps arriving for 30 days while you update the address elsewhere. The old address can't send in that time, and it isn't billed.

Can I use mailboxes for cold outreach?

No. Cold outreach isn't allowed. First contact goes through a check, and sales language, unfilled merge fields or the same message to more than 3 people in a day are refused.

Does it work over MCP?

Yes. The MCP server has tools to create mailboxes, wait for mail, search, reply and send. They return what the sender wrote inside a delimited block, apart from our checks, and leave out the raw bodies.

Put your agent's email on solid ground.

Start with three free mailboxes on a hosted address. Add your own subdomain when your agent needs to write first. Same API either way.