Protokol Mail
Protokol Mail is a built-in integration that lets you send transactional emails from your Protokol project. Emails are queued and delivered asynchronously with automatic retry and spam reporting.
Overview
Key characteristics:
- Async delivery — emails are queued and sent in the background with automatic retries (up to 3 attempts)
- HTML email support — send rich HTML emails with automatic content sanitization
- Attachments — supports file attachments via base64-encoded content or multipart form upload (max 5 attachments, 5MB each)
- Spam reporting — built-in spam report form for recipients to flag unwanted emails
- Rate limiting — configurable per-project rate limits (default: 100/hour, 1000/day)
- Pay-as-you-go — optional overage billing when rate limits are exceeded
- Workflow integration — use the
send-emailworkflow node or listen to email lifecycle events - Environment-aware — separate
devandliveenvironments for safe testing
Sending an Email
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
to |
string[] |
Yes | Recipient email addresses |
cc |
string[] |
No | CC email addresses |
bcc |
string[] |
No | BCC email addresses |
subject |
string |
Yes | Email subject line |
body |
string |
Yes | Email body (HTML) |
reply_to |
string |
No | Reply-to email address |
sender_name |
string |
No | Custom sender display name |
attachments |
AttachmentInput[] |
No | File attachments (see below) |
Attachment Input
| Field | Type | Description |
|---|---|---|
file_id |
string |
Optional DMS file ID reference |
file_name |
string |
File name |
mime_type |
string |
MIME type (e.g. application/pdf) |
content |
string |
Base64-encoded file content |
size |
number |
File size in bytes |
Response
{
"status": true,
"message_id": "550e8400-e29b-41d4-a716-446655440000",
"message": "Email queued for sending"
}
Sending with Attachments
import { Mail } from "@ptkl/sdk/beta"
import fs from "fs"
const mail = new Mail()
const pdfContent = fs.readFileSync("invoice.pdf")
const result = await mail.send({
to: ["billing@example.com"],
subject: "Invoice #123",
body: "<p>Please find your invoice attached.</p>",
reply_to: "billing@company.com",
sender_name: "Billing Department",
attachments: [{
file_name: "invoice.pdf",
mime_type: "application/pdf",
content: pdfContent.toString("base64"),
size: pdfContent.length,
}],
})
curl -X POST https://lemon.protokol.io/luma/integrations/v1/protokol-mail/emails \
-H "Authorization: Bearer $TOKEN" \
-F "to=billing@example.com" \
-F "subject=Invoice #123" \
-F "body=<p>Please find your invoice attached.</p>" \
-F "reply_to=billing@company.com" \
-F "sender_name=Billing Department" \
-F "file=@invoice.pdf"
Note
The multipart form endpoint accepts a maximum total payload of 25MB. Individual attachments are limited to 5MB each, with a maximum of 5 attachments per email.
Listing Emails
Retrieve a paginated list of email logs for your project, with optional status filtering.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
status |
string |
— | Filter by status: pending, sent, or failed |
page |
number |
1 |
Page number (1-indexed) |
limit |
number |
20 |
Items per page (max 100) |
Getting a Single Email
Email Log Fields
| Field | Type | Description |
|---|---|---|
message_id |
string |
Unique message identifier (UUID) |
project_uuid |
string |
Project scope |
tenant_uuid |
string |
Tenant scope |
component_uuid |
string |
Workflow component reference (if sent from workflow) |
env |
string |
Environment: dev or live |
from |
string |
Sender address (auto-generated) |
to |
string[] |
Recipients |
cc |
string[] |
CC recipients |
bcc |
string[] |
BCC recipients |
reply_to |
string |
Reply-to address |
subject |
string |
Subject line |
body |
string |
HTML body |
attachments |
string |
Attachment metadata (JSON) |
status |
string |
pending, sent, or failed |
retry_count |
number |
Number of send attempts |
max_retries |
number |
Maximum allowed retries (default: 3) |
error_message |
string |
Last error message (if failed) |
sent_at |
string |
Timestamp when successfully sent |
spam_reported |
boolean |
Whether reported as spam |
spam_reported_at |
string |
When spam was reported |
Resending a Failed Email
Re-queue a failed email for another delivery attempt.
Attachments
Listing Attachments
Downloading an Attachment
Returns the raw binary content with appropriate Content-Type and Content-Disposition headers.
Warning
Attachment binary content is automatically cleaned up after 7 days. Download attachments promptly if you need to retain them.
Permissions
All authenticated endpoints require RBAC permissions:
| Permission | Endpoints |
|---|---|
read protokol-mail |
List emails, get email, list attachments, download attachment |
send protokol-mail |
Send email, resend email |
Rate Limits
Each project has configurable rate limits based on the subscription tier:
| Setting | Default | Description |
|---|---|---|
| Emails per hour | 100 | Maximum emails sent per hour |
| Emails per day | 1000 | Maximum emails sent per day |
| Max body size | 500 KB | Maximum HTML body size |
| Max attachments | 5 | Maximum number of attachments per email |
| Max attachment size | 5 MB | Maximum size per individual attachment |
Note
If pay-as-you-go is enabled on your subscription, you can exceed rate limits — overage usage is billed separately on an hourly basis.
Workflow Integration
Send Email Node
Use the integration.protokol-mail.send-email workflow action node to send emails as part of a workflow. The node accepts the same fields as the API and queues the email for async delivery.
Email Events
The mail system publishes lifecycle events that can trigger workflows:
| Event | When |
|---|---|
protokol-mail.email.sent |
Email successfully delivered |
protokol-mail.email.failed |
Email permanently failed (max retries exceeded) |
protokol-mail.email.spam_reported |
Recipient submitted a spam report |
Spam Reporting
Each email footer includes a link to a spam report form. Recipients can report unwanted emails, which:
- Marks the email as spam-reported in the system
- Publishes a
protokol-mail.email.spam_reportedworkflow event - Displays a confirmation page to the reporter
Using in Platform Functions
You can send emails directly from platform functions using the SDK:
const { Mail } = $sdk.version('0.10')
const mail = new Mail()
const result = await mail.send({
to: [$input.body.email],
subject: "Your order has been confirmed",
body: `
<h1>Order Confirmed</h1>
<p>Hi ${$input.body.name},</p>
<p>Your order #${$input.body.order_id} has been confirmed.</p>
`,
})
response.json({
success: true,
message_id: result.message_id,
})
SDK Reference
The Mail class is available in both SDK versions:
// v0.10 (beta)
import { Mail } from "@ptkl/sdk/beta"
// v0.9 (stable)
import { Mail } from "@ptkl/sdk"
// Or via the Integrations facade
import { Integrations } from "@ptkl/sdk/beta"
const integrations = new Integrations()
const mail = integrations.getMail()
| Method | Description |
|---|---|
mail.send(input) |
Queue an email for sending |
mail.list(params?) |
List emails with optional filtering |
mail.get(messageId) |
Get a single email by ID |
mail.resend(messageId) |
Resend a failed email |
mail.listAttachments(messageId) |
List attachment metadata |
mail.downloadAttachment(messageId, attachmentId) |
Download attachment content |
For full type definitions, see the SDK TypeDoc reference.