Skip to content

Receive email

Create a receive-only Email instance with email.receive(options, handler).

Terminal window
import { email } from "@layeron/modules"
const inbound = email.receive({
name: "support",
namespace: "comms",
domain: "support.example.com",
}, async (message) => {
console.log({
from: message.from,
to: message.to,
cc: message.cc,
subject: message.subject,
text: message.text,
})
})
app.use(inbound)

domain is the Cloudflare email domain hostname. Layeron enables Cloudflare Email Routing DNS and updates the Email Routing catch-all rule for this instance during deploy.

The handler receives an EmailInboundMessage and a context object.

Terminal window
type EmailReceiveHandler = (
message: EmailInboundMessage,
context: EmailReceiveContext,
) => void | Promise<void>
FieldTypeDescription
idstringMessage ID from email headers or a generated local ID.
fromstringSender email address.
tostringRecipient email address.
ccstring[]CC recipient addresses.
bccstring[]BCC recipient addresses.
replyTostring | undefinedReply-To header value.
subjectstring | undefinedSubject header value.
textstring | undefinedPlain text body.
htmlstring | undefinedHTML body.
headersRecord<string, string>Normalized email headers keyed by lowercase name.
rawstringRaw email source.
receivedAtstringISO timestamp when Layeron received the message.
FieldTypeDescription
messageIdstringThe same message ID from the message.

The handler runs asynchronously. The inbound email is durably recorded before the handler runs.

Terminal window
layeron deploy

Layeron enables Cloudflare Email Routing DNS and updates the catch-all rule for the domain to route to the Email product Worker.

The deploy fails when Cloudflare cannot find the zone for domain in the connected account.

Run local dev, then call the inbound debug endpoint with the recipient address in the path.

Terminal window
curl -X POST \
"http://127.0.0.1:8787/cgi-bin/receive-email/support@mail.example.com" \
-H "content-type: application/json" \
-d '{
"from": "customer@example.com",
"cc": ["manager@example.com"],
"subject": "Need help",
"text": "Hello from local dev"
}'

The debug endpoint accepts these fields in the JSON body:

FieldType
fromstring
tostring
ccstring | string[]
bccstring | string[]
replyTostring
subjectstring
textstring
htmlstring
headersRecord<string, string>
messageIdstring
rawstring

Query parameters with the same names work for quick GET tests.

The endpoint responds with the processing result:

Terminal window
{
"status": "processed",
"messageId": "<layeron-...@local.layeron>"
}

status is processed when the handler ran, or ignored when no receive handler was configured for the domain.