Email in the platform is four nodes and one connection that carries two different things at once: the sending server (SMTP) and the mailbox server (IMAP or POP3). This is not a simplification for the form’s sake: at every provider those are two different hosts with different ports and different encryption, and splitting them would mean two connections to one mailbox that sooner or later disagree about the password.
The connection: two legs, one password
Created in Settings → Integrations, kind Email. The general mechanics (secret encryption, permissions, port-beats-field) are in the integrations overview.
Connection form fields
Fills in the hosts and ports. Login and password stay your job.
At Gmail, Yandex and Mail.ru this is an app password.
A different host from the mailbox one.
The Provider picker fills in both legs in one click. There are four presets, and they differ in more than host names:
| Provider | Mailbox (IMAP) | Sending (SMTP) | App password |
|---|---|---|---|
| Gmail | imap.gmail.com:993 | smtp.gmail.com:587 | required |
| Yandex Mail | imap.yandex.ru:993 | smtp.yandex.ru:465 | required |
| Mail.ru | imap.mail.ru:993 | smtp.mail.ru:465 | required |
| Outlook / Microsoft 365 | outlook.office365.com:993 | smtp.office365.com:587 | depends on policy |
The SMTP port decides how sending is encrypted: 465 encrypts from the first byte, 587 opens in the clear and upgrades to TLS. These are not interchangeable numbers — the wrong one means “does not send at all”, not “sends slower”.
The SMTP host must not be left empty. At all four providers above it differs from the mailbox host; with an empty field, sending falls back to the mailbox host and fails. The connection check does not fail over an empty field — it reports it as “not configured”: a connection created only for reading has no sending leg, and failing the check over that would be wrong.
IMAP or POP3. IMAP has folders, server-side search and a “seen” flag. POP3 has none of them: no folders, no search, no flags. Choosing POP3 is not “lighter”, it is poorer — three fields on the fetch node stop meaning anything (see below). Take IMAP whenever the provider offers it.
Four nodes
| Node | What it does |
|---|---|
| Email Config | picks a saved connection and hands it to the other nodes |
| Send Email | a graph step: builds a message from templates and sends it over SMTP |
| Fetch Emails | a graph step: pulls messages from the mailbox by a criterion |
| Email Tool | gives an agent send, fetch, search and reply as tools |
The connection arrives one of two ways: an Email Config node wired by a data edge into
the email_config port, or a connection picked in the working node’s own form. The port
beats the field. The port is required: with neither wired nor filled, the editor warns
and the run and deploy gates reject — the refusal arrives before a paid run reaches the
send.
Sending
Every field of the message is templated, meaning values from the run are substituted into
it: {{ inputs.input.email }} into the recipient, a model’s answer into the body. Two are
mandatory — recipient and subject; if the template in either resolves to an empty string the
node fails rather than sending a subject-less message to nobody.
The HTML switch decides how the provider renders the body: as markup or as literal text. The sender defaults to the connection’s login; the “from address” and “from name” fields in the node’s advanced section override it for one message. The platform always keeps the envelope address equal to the header address — otherwise the recipient’s SPF check treats the message as a forgery.
The node outputs a message_id — the identifier it assigned to the message itself. It is
what ties a sent message to a row in your own database.
Reading
The node pulls a batch of messages and returns them as a list. Each carries uid, subject,
sender, recipients, date, text body, HTML body and a “read” flag. Alongside: how many
messages arrived and which folder they came from.
What gets pulled is chosen by the “what to fetch” field:
| Mode | What is selected |
|---|---|
| Unread only | messages without the seen flag — the default |
| All messages | the whole folder, bounded only by the count |
| From a sender | messages whose From contains the given address |
| Since a date | messages delivered on or after a date (YYYY-MM-DD) |
| Raw IMAP criteria | a whole IMAP SEARCH expression — the escape hatch when four modes are not enough |
The count is capped at a hundred messages per call. Dates are parsed strictly: an unparsable date is rejected rather than quietly dropped — otherwise “since 1 July” would silently widen into “the whole folder”.
With POP3 selected, the three fields above mean nothing: the folder is always the inbox, the criterion is not applied, the flag is not set. The node does not hide this — its output leaves the “mailbox” field empty, so a downstream node cannot branch on a value that never existed.
Scenario: message → fields → record
The typical job looks like this: every N minutes pull the new messages, extract the fields you care about from each (who wrote, about which order, what they want) and put the result into a collection — or reply straight away.
- Execute + Data
- Data
-
Fetch Emails in “unread only” mode with marking as read left on. That is the protection against double processing: the next run will not see these messages.
-
A loop over the list — the fetch node returns a batch, and the model handles one message at a time. See Loops.
-
A model with structured output instead of a plain one: you describe the fields you want and get an object with those fields, not a paragraph you then have to parse.
-
A write to a collection, or a reply by mail. The reply is the same send node: the recipient comes from the parsed message, the subject gets a “Re:” prefix.
A message body can be long, and it travels into the model in full and is billed by tokens. On a noisy mailbox it is cheaper to cut the noise earlier — by sender, right in the fetch criteria, rather than after the fact.
Email as an agent tool
Email Tool gives the model four operations: send a message, fetch messages, search by
text and reply to a message by its uid. All four are on by default — unlike the
calendar, where some operations are off. Worth remembering: a freshly dropped email tool on
an agent means the model can send mail in your name.
- Execute + Data
- LLM
- Data
- Extension
- Execute + Data + Streaming
Three differences between the tool and the identically named nodes, all of which only show up in use:
- fetching through the tool never sets the seen flag. The model is looking at a mailbox, not draining a queue, and it must not silently eat your cursor;
- replying is two operations in one: the tool locates the original by
uiditself, takes the sender and subject from it and sends the answer. The model only needs auidand the text; - an error does not fail the run. The tool hands the model the error text together with a machine-readable code, and the model can correct itself — fix an address and try again. The code is what lets it tell “wrong password”, which is pointless to retry, from “server busy”, which is not.
Where this usually breaks
| Symptom | What happened | What to do |
|---|---|---|
| Check: mailbox opened, SMTP refused | the password is right, but sending goes to the wrong host or port | compare the SMTP host with the provider preset; ports 465 and 587 are not interchangeable |
| Check: "could not connect" on both legs | an account password was entered | issue an app password in the provider's security settings |
| Check says "SMTP not configured" | the SMTP host field is empty | fill it in — with it empty, sending goes to the mailbox host and fails |
| Every run brings the same messages | "mark as read" is off while the mode is "unread only" | turn it on; it is the processing cursor |
| Message sent with no subject / node fails on "Subject is required" | the subject template resolved to an empty string | check that the source node really produces the field; inspect the run to see what it held |
| POP3 selected, "from a sender" filters nothing | POP3 has no server-side search — the criterion is ignored | switch to IMAP, or filter after fetching |
| An attachment never reached the graph | the fetch node parses text and HTML only | attachments are not supported; ask for a link instead of a file |
| The run is rejected: a required port on the node is not wired | the email_config port is empty and no connection is picked in the form | wire an Email Config into the port or pick a connection in the form — the port is required, so this is a warning in the editor and an error at the run and deploy gate |
| The agent says email is unavailable | a connection is picked but does not answer or does not fit | the tools are advertised to the model either way, and without a working connection the call returns it a textual error — read the tool-call text in the run |
What next
Integrations: overview
How connections are stored and who may change them.
Scheduled runs
So the mailbox is checked by itself, not by a button.
Agents and tools
Tool permissions, rounds, budgets.
Collections
Where the parsed messages go.
Templates and variables
How recipient and subject are assembled from run data.
Node reference
Full schemas for all four email nodes.