Inbound Email Automations
Rules that tag, assign, and auto-reply the moment a new ticket or conversation is created from an inbound email.
Overview
Automations are trigger-action rules. Each rule has an event (what it listens for), conditions (what must match), and actions (what it does). They run in the background right after a new ticket or conversation is persisted and before outbound notifications.
Rules are workspace-scoped and only owners can create, edit, or reorder them.
Events
| Event | Fires when |
|---|---|
ticket_created | A new ticket is created from an inbound email (ticket-purpose address). |
conversation_created | A new conversation is created from an inbound email (inbox-purpose address, shared or personal). |
Conditions
All conditions on a rule must match (AND semantics). String comparisons are case-insensitive; body comparisons strip HTML before matching.
| Type | Operator | Value |
|---|---|---|
from_email | equals (default) | Exact address, e.g. [email protected] |
from_email | domain | Bare domain, e.g. acme.com (matches any sender at that domain) |
subject_contains | — | Substring, e.g. urgent |
body_contains | — | Substring, matched against the plaintext body |
contact_list | in / not_in | list_id of a Contact List. Matches when the sender's contact is (or isn't) a member. Sender list memberships are pre-resolved once per rule run, so the check is O(1) per evaluation. |
Actions
| Type | Parameters | Behavior |
|---|---|---|
add_tag | tag_id | Attaches a workspace-scoped tag to the ticket or conversation. |
assign_agent | user_id | Assigns the ticket or conversation to a workspace member. Non-members are silently skipped. |
send_response | body | Sends a templated auto-reply from a sendable workspace email. Per-recipient cooldown of 60 minutes prevents loops. |
Template variables for send_response
The body of a send_response action supports Mustache-style placeholders. Unknown variables are left intact.
{{contact.name}},{{contact.email}}{{ticket.id}},{{ticket.subject}}{{conversation.id}},{{conversation.subject}}{{workspace.name}}
Execution Order
Within a single event, rules run in ascending priority order (lower numbers run first). Set stop_on_match to true on a rule to short-circuit remaining rules once it matches. Inactive rules (is_active = false) are skipped.
Every match increments the rule's match_count and updates last_matched_at. A successful match also logs an automation_applied entry on the ticket or conversation activity timeline.
Cooldown
The send_response action checks the last 60 minutes of automated messages to the same recipient within the workspace. If one exists, the action is skipped. This applies even if the earlier automated message was never successfully delivered, so it's a hard guarantee against auto-reply loops.
Creating a Rule via API
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Urgent auto-reply",
"event": "conversation_created",
"is_active": true,
"priority": 10,
"stop_on_match": false,
"conditions": [
{ "type": "subject_contains", "value": "urgent" },
{ "type": "from_email", "operator": "domain", "value": "acme.com" }
],
"actions": [
{ "type": "add_tag", "tag_id": 12 },
{ "type": "assign_agent", "user_id": 3 },
{ "type": "send_response",
"body": "Hi {{contact.name}}, we got your message and will respond shortly." }
]
}' \
/api/v1/workspaces/WORKSPACE_ID/automations Testing a Rule
Use the dry-run endpoint to verify a rule matches a payload without creating tickets, tags, or sending any email.
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from_email": "[email protected]",
"subject": "Urgent: site down",
"body": "Production is offline"
}' \
/api/v1/workspaces/WORKSPACE_ID/automations/RULE_ID/test The response includes matched (boolean) and a trace of each condition's result.
Reordering Rules
Send an ordered list of rule IDs to reorder priorities in bulk:
POST /api/v1/workspaces/{id}/automations/reorder
{ "ids": [3, 1, 2] } Endpoints
GET /workspaces/{id}/automations— listPOST /workspaces/{id}/automations— create (owner only)GET /workspaces/{id}/automations/{rule}— showPUT /workspaces/{id}/automations/{rule}— update (owner only)DELETE /workspaces/{id}/automations/{rule}— delete (owner only)POST /workspaces/{id}/automations/{rule}/test— dry-run match against a sample payloadPOST /workspaces/{id}/automations/reorder— bulk reorder by priority (owner only)
Frequently Asked Questions
Do automations run retroactively on existing tickets?
No. Automations fire only on fresh ticket_created and conversation_created events. To act on existing tickets, use the REST API directly.
What is the cooldown on auto-replies?
Sixty minutes per recipient per workspace. The send_response action checks for any automated message to the same address within the last 60 minutes and skips if one exists, which prevents auto-reply loops.
Can I test a rule before it runs live?
Yes. Send a sample payload to POST /workspaces/{id}/automations/{rule}/test. The response includes a matched boolean and a trace of each condition's result. Nothing is persisted.
What happens when two rules match the same inbound email?
Rules run in ascending priority order (lower numbers first). Set stop_on_match to true on any rule to halt the chain once it matches.
Who can manage automations?
Workspace owners only. Creating, editing, reordering, and deleting automations requires the owner role. Members can view rules and results.
Can I route a rule based on a Contact List?
Yes. Use the contact_list condition with operator in or not_in and a list_id. The check matches when the sender's contact is (or isn't) a member of that list. Deleting a list while it's referenced by any rule returns 409 Conflict — remove the condition first.
Related
- Email Pipeline — how inbound email becomes a ticket or conversation
- Webhooks — for reacting to events in your own services
- API Reference — complete endpoint schema