Receiving Emails
Create inboxes, wait for emails in real-time, and filter results.
Last updated 2026-03-29
Every LobsterMail inbox is a fully functional email address your agent can receive mail at. This guide covers inbox creation, real-time email delivery, filtering, and the email object structure.
Creating Inboxes#
// Smart naming (recommended) — handles collisions automatically
const inbox = await lm.createSmartInbox({
name: 'Sarah Shield',
org: 'Palisade',
displayName: 'Sarah Shield',
});
// Tries: sarah-shield, sarah-shield-palisade, s-shield, sarah-shield1..5, then random
// Purpose-based
const inbox = await lm.createSmartInbox({
preferred: ['billing-bot', 'billing'],
displayName: 'Billing Bot',
});
// Auto-generated address
const inbox = await lm.createInbox();
console.log(inbox.address); // lobster-a7f3@lobstermail.ai
// Custom local part
const inbox = await lm.createInbox({ localPart: 'signup-bot' });
console.log(inbox.address); // signup-bot@lobstermail.ai
Custom local parts are first-come, first-served. If the address is taken, the request will fail with a 409 Conflict. Use createSmartInbox() to handle collisions automatically.
Dots are cosmetic (Gmail-style): sarah.shield and sarahshield are the same mailbox.
Listing Emails with receive()#
receive() returns an array of emails currently in the inbox.
const emails = await inbox.receive();
Options#
| Option | Type | Description |
|---|---|---|
since | string | Only return emails received after this ISO 8601 timestamp. |
limit | number | Maximum number of emails to return. Default: 20, max: 50. |
direction | 'inbound' | 'outbound' | Filter by email direction. |
const recent = await inbox.receive({
since: '2026-02-23T00:00:00Z',
limit: 5,
});
Waiting with waitForEmail()#
waitForEmail() waits for an email matching your filters and returns it as soon as it arrives. Under the hood, it uses server-side long-polling — the server holds the connection open and responds within milliseconds of the email landing, instead of the client polling every few seconds.
const email = await inbox.waitForEmail({
filter: { from: 'noreply@acme.com', subject: 'Verify' },
timeout: 60000, // 60 seconds
});
If no matching email arrives within the timeout, waitForEmail() returns null.
Options#
| Option | Type | Default | Description |
|---|---|---|---|
filter.from | string | — | Match against the sender address (exact match). |
filter.subject | string | RegExp | — | Match against the subject line. |
timeout | number | 60000 | Max wait time in milliseconds. |
since | string | — | Only consider emails after this ISO 8601 timestamp. |
longPoll | boolean | true | Use server-side long-polling for real-time delivery. Set to false to use classic exponential-backoff polling. |
How Long-Polling Works#
When longPoll is enabled (the default), the SDK calls GET /v1/inboxes/{id}/emails/poll which holds the request open server-side for up to 25 seconds. When an email arrives for that inbox, the server returns it immediately — typically within 200ms of delivery.
If no email arrives within the 25-second window, the server returns 204 No Content and the SDK automatically retries. This means your agent makes ~2-3 HTTP requests per minute while waiting, instead of 10+ with traditional polling.
The SDK automatically falls back to classic polling if the server doesn't support the long-poll endpoint.
The Email Object#
email.id // string — unique email ID (e.g. eml_...)
email.inboxId // string — the inbox that received this email
email.direction // 'inbound' | 'outbound'
email.from // string — sender address
email.to // string[] — recipient addresses
email.subject // string — subject line
email.body // string | null — full body (null until fetched)
email.preview // string | null — first 200 characters, text only
email.threadId // string | null — conversation thread ID
email.receivedAt // string | null — when the email was received
// Security (see Security guide)
email.isInjectionRisk // boolean — true if injection risk detected
email.security.injectionRiskScore // number — 0.0 to 1.0
email.security.flags // string[] — e.g. ['prompt_injection', 'phishing_url']
email.security.spf // string | null — 'pass' | 'fail' | 'none'
email.security.dkim // string | null — 'pass' | 'fail' | 'none'
email.security.dmarc // string | null — 'pass' | 'fail' | 'none'
Safe Content Access#
For agents passing email content to an LLM, always use safeBodyForLLM() instead of body:
const safeContent = email.safeBodyForLLM();
This wraps the body in boundary markers and strips dangerous patterns. See the Security guide for details.
Searching Across Inboxes#
Need to find an email but don't know which inbox it's in? Use searchEmails() to search across all inboxes at once:
const results = await lm.searchEmails({ q: 'invoice', from: 'billing@' });
See the Cross-Inbox Search guide for full details on filtering, pagination, and query syntax.
Conversation Threads#
Emails are automatically grouped into conversation threads. Use the threadId on any email to find related messages, or browse threads directly:
const { data: threads } = await inbox.listThreads();
const thread = await inbox.getThread(threads[0].id);
See the Threads guide for details on how threading works and how to reply within a thread.
Pagination#
Use the since parameter to paginate through emails. receive() returns an Email[] array — use the timestamp of the last email as the since value for the next page:
const page1 = await inbox.receive({ limit: 10 });
if (page1.length === 10) {
const lastEmail = page1[page1.length - 1];
const page2 = await inbox.receive({ limit: 10, since: lastEmail.receivedAt });
}