HCC Docs

Email flows

An Email flow answers inbound Email to one of your addresses with your code, as a Text flow does for Texts. It runs once the Email is stored and in its Thread, so if your server is down, the Thread stays with its Owner, or with nobody.

export const help = defineEmailFlow('help', { addresses: ['help@acme.com'] }).onEmail(
  (email, c) => {
    if (/invoice/i.test(email.subject ?? '')) return c.queue('billing');
    if (email.autoReply) return; // an out-of-office: leave it be
    return c.reply({ text: 'Thanks, we have your message and will answer within a day.' });
  },
);
ReturnWhat happens
c.assign(repId)That Rep owns the Thread, and their desk hears it.
c.queue(queue)Labels an unowned Thread with the queue's name for your reps to pick up. Nothing routes it.
c.reply({ text, html?, subject? })We send it in the Thread, from the address it came to, once per inbound Email. Re: by default.
c.unsubscribe()Suppresses the sender's address, as manual.
NothingThe Thread stays where it is.

email has from, to, cc, subject, text, hasHtml, the names and sizes of its attachments, inReplyTo and autoReply. Read the HTML or the files with hcc.emails.get(email.id). A reply goes through every check any Email does. A reply to an automatic answer is never sent, so two machines can't answer each other for ever: it's logged as auto_reply, and testEmailFlow says so with refused: 'auto_reply'. An unsubscribe never reaches an Email flow.

hcc deploy or hcc.emailFlows.deploy makes them take Email. hcc.serve({ emailFlows }) serves them and warns about one that isn't deployed. On a live hcc deploy, addresses binds them too, which takes emails:write, and an address that isn't in your workspace stops the deploy. A deploy never unbinds an address. To bind by hand: hcc.emailAddresses.update(id, { emailFlow: 'help' }), or null to unbind. Settings → Email shows which flow an address runs. In test, an Email runs the only Email flow deployed. If there are several, none runs.