Loopfour
Triggers

Inbound email trigger

Start a workflow from inbound email: the address format, the payload a run receives and how attachments are passed to later steps.

The inbound email trigger gives a workflow its own email address. Each email sent to it starts one run, with the sender, subject, body and PDF attachments in the run input. Vendors can send bills there, or you can forward them from a shared AP inbox. The Studio walkthrough is Start a workflow from an email.

Configuration

{
  "trigger": {
    "type": "email_event",
    "filters": {
      "fromAllowlist": ["billing@northwind.example", "ap@birch.example"],
      "subjectContains": "invoice",
      "requireAttachment": true
    }
  }
}
FieldTypeMeaning
type"email_event"
addressstringSet by Loopfour on activation. Do not set it yourself
filters.fromAllowlistemail arrayOnly these senders start a run. Exact match, ignoring case
filters.subjectContainsstringOnly subjects containing this text start a run, ignoring case
filters.requireAttachmentbooleanOnly emails with at least one stored PDF start a run

All filters are optional. When several are set, an email must pass all of them.

In Studio this is the Inbound Email block. It has one per workflow, a read-only Inbound Address field and a Filters section.

The address

The address has the form wf_<token>@inbound.loopfour.ai, with a random token. It is created when the workflow is first activated (Deploy in Studio). Before that, Studio shows "Address generated on deploy." After activation, GET /workflows/:id returns it in trigger.address, and Studio shows it with a Copy address button.

Deploying again keeps the same address. Archiving or deleting the workflow, or changing it to another trigger type, turns the address off.

What happens to an email

  1. The email arrives and its delivery signature is checked. Unsigned deliveries are dropped.
  2. Mail to an unknown or inactive address is dropped.
  3. Rate limits apply: 10 emails a minute per address and 60 per company. Emails over the limit are dropped.
  4. The workflow must be active. Mail that arrives while it is a draft, paused or archived does not start a run and is not kept. Ask the sender to send it again.
  5. Filters are checked. When fromAllowlist is set, an email whose SPF or DKIM result is a hard fail is dropped first, so a forged sender address cannot get through the list.
  6. PDF attachments are stored as workspace files.
  7. One run starts, recorded with triggerType: "webhook".

Each email starts at most one run per workflow, even when it is delivered more than once.

Attachments

  • Only application/pdf attachments are stored. Other types are skipped.
  • An attachment over 25 MB is skipped.
  • Skipped attachments do not stop the run, unless requireAttachment is true and no PDF was stored.
  • Each stored PDF is a workspace file. Later steps use its fileId, for example with the PDF block or the Workspace Files block.

Run input

{
  "inboundEmail": {
    "source": "inbound-email",
    "emailId": "4ef9a1b2-...",
    "to": "wf_k3j9q2m8x7@inbound.loopfour.ai",
    "from": "billing@northwind.example",
    "fromName": "Northwind Billing",
    "subject": "Invoice NW-2291 for October",
    "text": "Please find our invoice attached.",
    "html": "<p>Please find our invoice attached.</p>",
    "receivedAt": "2026-11-03T14:05:22.000Z",
    "auth": { "spf": "pass", "dkim": "pass" },
    "attachments": [
      {
        "fileId": "550e8400-e29b-41d4-a716-446655440000",
        "name": "NW-2291.pdf",
        "contentType": "application/pdf",
        "size": 204800
      }
    ]
  }
}
FieldMeaning
from, fromNameSender address and display name. Treat both as untrusted text
subjectSubject line, cut to 998 characters. Empty string when missing
text, htmlBody, each cut to 1,000,000 characters. Either can be missing
receivedAtWhen the email was received
auth.spfpass, fail, softfail, neutral, none or unknown
auth.dkimpass, fail, neutral, none or unknown
attachmentsStored PDFs. Empty when there were none

Steps read these as {{input.inboundEmail.<field>}}:

{
  "fileId": "{{input.inboundEmail.attachments.0.fileId}}",
  "note": "From {{input.inboundEmail.from}}: {{input.inboundEmail.subject}}"
}

Read the email with {{input.inboundEmail…}}. The run engine's trigger root holds only connectionId, so a reference that starts with trigger.inboundEmail resolves to an empty value.

Things to check when an email did not start a run

  • The sender used the exact address shown in Studio.
  • The workflow is active.
  • The sender is on fromAllowlist, and the email passed SPF and DKIM.
  • The subject contains the subjectContains text.
  • With requireAttachment, the email had a PDF of 25 MB or less.
  • The address and company rate limits were not reached.

On this page