Email triggers
A trigger sends one project email when a selected event fires. Use it for notifications such as “email the owner when an order is created”. Triggers use the same events as webhooks and run next to them: an event that reaches your webhooks also reaches your triggers, and a failed email never fails the original API call.
Configure triggers in the console under Database → Automation → Triggers, or with the admin API below. The Automation tab has two sub-tabs, Webhooks and Triggers.
Sender
Section titled “Sender”Mail goes out from the project’s own address, for example "Acme Shop" <acme-shop-a1b2c3@tefily.com>. The display name is the project name, and the address is shown in Project Settings → Project details. There is no inbox behind the address, and you cannot choose a different sender or a reply-to.
Events
Section titled “Events”Pick at least one of the events on Webhooks, except webhook.ping. Collections work as they do for webhooks: leave the list empty for every collection. Auth events ignore the collection filter.
Recipient
Section titled “Recipient”| Mode | recipientMode |
Setting | Meaning |
|---|---|---|---|
| Fixed address | value |
recipientValue |
Always the same address. |
| From the record | record |
recipientField |
Read the address from the event data. |
This mirrors the “compare with a record field or a static value” choice in access rules.
For recordField, a bare name (email, ownerEmail) is looked up on the record, then on the user, then on the event data itself. A dotted name (record.ownerEmail, user.email) starts at the event data. Auth events carry the end user, so email resolves to the user’s address.
Bulk events (record.created_many, and so on) have no single record, so a trigger that reads its recipient from the record is skipped for them. A fixed address sends once per event.
If the field is missing or is not a valid email address, the send is skipped and the reason is logged on the trigger. It never fails the original request.
Message
Section titled “Message”subjectTemplate and bodyTemplate accept placeholders in double braces. Unknown placeholders render empty.
| Placeholder | Value |
|---|---|
{{event}} |
The event name |
{{collection}} |
The collection, empty for auth events |
{{projectName}} |
The project name |
{{timestamp}} |
When the event fired (UTC) |
{{record.title}} |
A field of the record. Any field works. |
{{user.email}} |
A field of the end user, for auth events |
Set bodyIsHtml to send the body as HTML. Substituted values are HTML-escaped, the template itself is not. Otherwise the body is plain text. Subjects are one line, at most 200 characters. Values are cut at 2,000 characters.
Limits
Section titled “Limits”- At most 20 triggers per project. Create beyond the cap fails with
A project may have at most 20 email triggers. - Each trigger email counts toward
max_transactional_emails_per_day, the same daily cap as the send API. Over the cap the email is not sent and the run is logged asfailed.
See Usage and limits.
Run log
Section titled “Run log”Every attempt is recorded on the trigger with sent, skipped, or failed, the event, the recipient, and the reason. The console shows the latest 50. Runs older than 30 days are removed over time.
Admin API
Section titled “Admin API”Requires a platform JWT or PAT with schema read (list, get, runs) or schema update (create / update / delete / test).
| Method | Path |
|---|---|
| GET / POST | /api/projects/:projectId/email-triggers |
| GET / PATCH / DELETE | /api/projects/:projectId/email-triggers/:id |
| GET | /api/projects/:projectId/email-triggers/:id/runs |
| POST | /api/projects/:projectId/email-triggers/:id/test |
POST /api/projects/YOUR_PROJECT_ID/email-triggersAuthorization: Bearer kfx_…Content-Type: application/json
{ "name": "New order", "events": ["record.created"], "collections": ["orders"], "recipientMode": "record", "recipientField": "customerEmail", "subjectTemplate": "Order {{record.number}} received", "bodyTemplate": "Thanks, we have your order {{record.number}}.", "bodyIsHtml": false, "isActive": true}test sends the templates once to the signed-in user, with sample data, so you can check the sender and wording without firing a real event. It counts toward the daily cap.