Appearance
Email node
The Email node sends a transactional email — an order confirmation, a contact-form notification, a password reset — through the Resend provider. It's an I/O node, so it can fail on the provider's side and carries an error port.
Component id: flowrunner/email.
IMPORTANT
This node is an installable component, not part of the engine. Every workspace gets it installed automatically; if it has been removed, the node passes straight through at run time and the editor marks it Not installed in the Add panel. Open Components in the project header to reinstall it.
How it works
The node resolves its fields, then posts to Resend. Because it runs as a component, ${env.X} is not resolved — a component never sees the server environment — so the API key comes from the workspace secret vault as RESEND_API_KEY. Flow refs like ${start.email} interpolate as normal.
to— the recipient address. Required; a missing recipient fails the node (email: missing recipient).subject— the subject line.body— the HTML body of the message.
WARNING
Changed: the node used to read the server's RESEND_API_KEY and, when none was set, quietly record a no-op instead of failing. It now requires RESEND_API_KEY in the workspace secrets and takes the error port when it is missing (missing API key). A send node that silently does not send is worse than one that tells you — but if you relied on the old behaviour, wire the error port.
The result is stored under resultVar (default email):
text
{ sent: true, id: <provider message id | null> }| Outcome | sent | id |
|---|---|---|
| Sent successfully | true | the provider's message id |
No RESEND_API_KEY in the workspace secrets | — | fails on the error port |
| Provider rejected the send | false | "provider_error_<status>" |
| Send threw | false | the error message |
Config
| Field | Required | Description |
|---|---|---|
to | Yes | Recipient email address. Resolves ${env.X} / ${secrets.X}. Missing recipient fails the node. |
subject | No | Subject line. Resolves ${env.X} / ${secrets.X}. |
body | No | HTML body of the email. Resolves ${env.X} / ${secrets.X}. |
resultVar | No (default email) | Variable the { sent, reason } result is stored under. |
retries | No (default 0) | Retry a failed send up to this many times (max 5). See Retrying transient failures. |
retryDelayMs | No | Milliseconds to wait between retries. |
NOTE
The to, subject, and body fields only resolve ${env.X} and ${secrets.X} — they do not interpolate flow references like ${start.name}. To personalise a message from request data, build the string in a Template node first, then pass its result to the Email node.
Ports
| Port | Followed when |
|---|---|
next | The send completed or was a graceful no-op. Check email.sent to know which. |
error | Only when the send throws an unexpected error, or when the recipient is missing. |
Because a missing provider key is a no-op (not a failure), the error port is reserved for genuinely unexpected problems. To react to an unsent message in normal operation, branch on email.sent with an If node.
Example
Notify the business when a contact form is submitted:
text
Template var: html template: "<p>New message from ${start.email}: ${start.message}</p>"
Email to: ${env.OWNER_EMAIL} subject: "New contact form" body: html.valueTIP
Server email delivery is turned on with RESEND_API_KEY (and an EMAIL_FROM sender). See Environment variables for how to configure it. Until then, the Email node runs as a safe no-op.