Channels.email.send. Two modes exist: a generated inbox, where Lua creates the address from a display name you choose, and an existing address, where you forward mail from your own mailbox to an address Lua gives you. Both are available in the admin dashboard and in lua channels.
Verified against lua-cli 3.33.0.
Before you begin
- A display name for the agent’s mail, shown in the
Fromheader. - For an existing address: access to that mailbox’s forwarding settings, or to your mail provider’s routing rules.
- An agent with a promoted production version; see Release an agent.
1
Link the address
- Dashboard
- CLI
In the admin dashboard open Agents, select the agent, select + in the Channels section of its Overview tab, and choose Email in Connect a channel. Under Connection type pick Generate new email or Use existing email, enter the Display name (and, for an existing address, the Email address), and select Connect. Email Channel Created then shows the new address; Email Channel Connected shows the address to forward your mail to, with forwarding steps for Gmail and Outlook.
2
Provider console: forward your mail (existing address only)
In your mail provider, forward everything that arrives at your address to the forwarding address Lua printed. Gmail and Google Workspace send a confirmation to the forwarding address before they activate it; the agent receives that confirmation, so complete the step from the provider’s side. Until forwarding is active, nothing reaches the agent.
3
Verify
Send an email to the connected address with the subject
Test and a question in the body. The reply arrives in the same thread with subject Re: Test. The inbound turn is in the agent’s logs.Channel behavior
Lua.request.webhook.payload is typed unknown; narrow it before reading fields. On a generated inbox the payload is the provider’s message object instead, with snake_case fields such as message_id, in_reply_to, references, subject, from, to, cc, text, and attachments.
Send email from code
Channels.email.send takes a recipient as email (any address) or userId (resolved from the end user’s history), an optional subject, and exactly one body: text as plain text, html sent as-is, or richBody, Markdown and ::: components rendered into the same branded template the agent’s replies use. cc, bcc, and attachments (fetched from a URL server-side) are optional. To keep a follow-up in an existing thread, pass the inbound email’s messageId as inReplyTo and its chain in references; these are honored on the forwarding channel.
src/tools/SendReceiptTool.ts
messageId is the provider’s message ID and status is accepted when the call returns; see the Channels reference.
Settings
Open Agents, select the agent, and in the Channels section of its Overview tab select the email channel. The panel shows the channel’s status first, then every setting with its default. A toggle saves when you flip it and can be undone from the confirmation; a text or list field saves when you leave it. Change history lists who changed which setting, and when. The status shows the sending address and, for an existing address, whether Amazon SES has verified it and the forwarding address to send your mail to. It also shows when the last email arrived and, once your mail rule copies colleagues’ replies to Lua (see Human takeover), when the last copy arrived. These times are recorded from 30 September 2026; mail that arrived earlier isn’t counted.
A generated inbox has only the two settings marked Both.
To change settings from code, send only the keys you change.
null resets a setting to its default; a setting without a default, such as the sender name, can’t be reset. The response is the channel’s full status and settings, each with its value and its source: stored, default, or derived. <channel> is the channel’s id or its address.
400 with errors, keyed by setting, and changes nothing. GET on the same path reads the settings, and GET …/settings/history lists past changes, newest first. Changing settings needs the Builder role on the agent; Operators can read them.
Human takeover
With human takeover on, a colleague who replies to a customer takes that conversation over. While the conversation is held, the agent stores the customer’s messages but doesn’t reply and runs nothing, not even a model call. Takeover is off by default and set per channel; on email it works on a channel linked to an existing address. The colleague’s message is saved in the conversation, marked as written by a colleague and already sent to the customer, so the agent sees it on later turns. The admin dashboard shows it as a colleague’s message. A message an operator sends to the customer from the admin dashboard also holds the conversation, except when thread scoping is on. Turn it on, and set how long the pause lasts and which domains count as colleagues, in Settings. On other channels the pause length defaults to 24 hours on WhatsApp, Instagram, Messenger, and SMS, 30 minutes on web chat and Front, and 24 hours anywhere else.How a colleague’s reply is detected
Without setup. When a customer replies to an email the agent never sent or received, Lua reads the part the customer’s mail quoted. If it shows the email came from one ofstaffDomains, or shows only a name, the conversation is held and the quoted text is saved as the colleague’s message. If the quoted author is someone else, such as another person on CC, nothing is held. In this mode Lua learns of the colleague’s reply only when the customer answers it.
With a mail rule. One rule in your own mail system copies every email sent from the channel’s address to Lua. The colleague’s full reply then reaches Lua within seconds, and the conversation is held before the customer answers.
1
Provider console: create a rule for mail sent from the channel's address
In Exchange or Microsoft 365, create a transport rule; in Google Workspace, create a routing rule. Make it match mail sent from the address the channel answers for, for example
[email protected]. 2
Provider console: Bcc the forwarding address
Set the rule’s action to add a Bcc recipient: the forwarding address Lua gave you when you linked the channel.
3
Verify
With Pause the agent when a colleague replies on, reply from the channel’s address to a customer who already has a conversation with the agent. Within seconds the admin dashboard shows your reply in that conversation as a colleague’s message, and the customer’s next email is stored without an answer from the agent.
Thread scoping
Withemail.threadScoping off, an email channel keeps one conversation per sender, so a hold covers everything that customer sends. With it on, each email thread is its own agent conversation, and a colleague’s reply holds only that thread. Change it in Settings.
Hand the conversation back
The hold ends on its own onceidleReleaseMinutes pass without a colleague reply; every colleague reply starts the wait again. To end it sooner, open the conversation in the admin dashboard and select Hand back. The agent then answers again.
Sending while a conversation is held
Channels.send, Channels.whatsapp.sendTemplate, Channels.whatsapp.sendReaction, Channels.email.send, and the REST send routes refuse a proactive send to a held conversation with HTTP 409 and the code CONVERSATION_HELD, whether the end user is addressed by user ID or by phone number. Pass options: { ignoreHold: true } to send anyway; the option is in lua-cli’s types from the next lua-cli release. A message sent with user.send() while the conversation is held is not delivered, and has no override: hand the conversation back first. For email, a send with inReplyTo is checked against that thread’s conversation, and a send without thread context against the customer’s default conversation.
Limits
- Generated address: the local part is the display name lowercased, with spaces and underscores turned into hyphens, other characters except letters, digits,
.and-removed, and cut to 30 characters; a four-character suffix is added if the name is taken.Support Teambecomessupport-team@…. - Outbound attachments: the raw bytes of all attachments on one email total at most 28 MB.
- Inbound embedded images: at least 1 KB each, at most 10 per email.
- Linking an existing address a second time doesn’t create a second channel: the channel already registered for that address is updated, including the agent it belongs to, and the same forwarding address is returned. Each generated-inbox link creates a new inbox.
Troubleshooting
Nothing arrives on an existing address
Nothing arrives on an existing address
Forwarding isn’t active. Check the provider’s forwarding rule and, for Gmail or Workspace, that the forwarding address was confirmed. Test by emailing your own address, not the forwarding address.
email send requires a text, html, or richBody body
email send requires a text, html, or richBody body
Channels.email.send was called with none of the three bodies. Pass exactly one.Attachments exceed the 28MB limit
Attachments exceed the 28MB limit
The attachments on one email add up to more than 28 MB of raw data. Split them across emails or link to the file instead.
Next steps
Send proactive messages
Receipts, reports, and reminders from jobs and webhooks.
Channels reference
Every field of
Channels.email.send and the delivery status model.Response formatting
What each component becomes in email.
About channels
The inbound and outbound channel vocabularies.

