Skip to main content

Send transactional email

curl -u 'username:password' 'https://listmonk.mysite.com/api/tx' \
  -H 'Content-Type: application/json' \
  -d '{
    "subscriber_emails": ["user@example.com"],
    "template_id": 1,
    "data": {
      "username": "john_doe",
      "verification_code": "ABC123"
    },
    "content_type": "html"
  }'
Sends transactional emails to one or more recipients using a predefined template. Authentication: Required
Permission: tx:send

Request Body

template_id
integer
required
ID of the transactional template to use
subscriber_mode
string
default:"default"
Subscriber lookup mode:
  • default: Look up subscribers in database (fail if not found)
  • fallback: Look up in database, create ephemeral subscriber if not found
  • external: Don’t look up in database, always use ephemeral subscribers

Subscriber Identification (choose one)

subscriber_emails
array
Array of email addresses to send to
subscriber_ids
array
Array of subscriber IDs from database (not available in external or fallback mode)
subscriber_email
string
Single email address (deprecated, use subscriber_emails instead)
subscriber_id
integer
Single subscriber ID (deprecated, use subscriber_ids instead)

Email Configuration

data
object
Custom data to pass to the template (accessible as .Tx.Data.key in template)
from_email
string
From email address (defaults to system setting)
subject
string
Override template subject (optional if template has subject)
content_type
string
default:"html"
Content type: html or plain
messenger
string
default:"email"
Messenger backend to use
headers
array
Custom email headers (array of objects with key-value pairs)

Response

data
boolean
Returns true on successful queueing of emails

Subscriber Modes

Default Mode

Looks up subscribers in the database and fails if not found.
{
  "subscriber_mode": "default",
  "subscriber_emails": ["existing@example.com"],
  "template_id": 1
}
Use case: Sending to known subscribers only (e.g., password reset for registered users)

Fallback Mode

Attempts to look up subscribers in the database. If not found, creates an ephemeral subscriber with the provided email.
{
  "subscriber_mode": "fallback",
  "subscriber_emails": ["anyone@example.com"],
  "template_id": 1
}
Use case: Sending to both registered and unregistered users (e.g., contact form responses)

External Mode

Doesn’t look up subscribers in the database. Always creates ephemeral subscribers.
{
  "subscriber_mode": "external",
  "subscriber_emails": ["external@example.com"],
  "template_id": 1
}
Use case: Sending to external recipients not in your subscriber database (e.g., notifications to administrators)
Ephemeral subscribers exist only for the duration of the email send and are not stored in the database.

Examples

Welcome Email

curl -u 'username:password' 'https://listmonk.mysite.com/api/tx' \
  -H 'Content-Type: application/json' \
  -d '{
    "subscriber_emails": ["newuser@example.com"],
    "template_id": 2,
    "data": {
      "username": "newuser",
      "account_url": "https://example.com/dashboard"
    }
  }'
Template (template_id: 2):
<!DOCTYPE html>
<html>
<body>
  <h1>Welcome {{ .Subscriber.Name }}!</h1>
  <p>Your username is: <strong>{{ .Tx.Data.username }}</strong></p>
  <p><a href="{{ .Tx.Data.account_url }}">Go to your dashboard</a></p>
</body>
</html>

Password Reset

curl -u 'username:password' 'https://listmonk.mysite.com/api/tx' \
  -H 'Content-Type: application/json' \
  -d '{
    "subscriber_emails": ["user@example.com"],
    "template_id": 3,
    "subject": "Reset Your Password",
    "data": {
      "reset_url": "https://example.com/reset?token=abc123xyz",
      "expires_in": "1 hour"
    }
  }'
Template:
<!DOCTYPE html>
<html>
<body>
  <h1>Password Reset Request</h1>
  <p>Hi {{ .Subscriber.FirstName }},</p>
  <p>Click the link below to reset your password:</p>
  <p><a href="{{ .Tx.Data.reset_url }}">Reset Password</a></p>
  <p>This link expires in {{ .Tx.Data.expires_in }}.</p>
</body>
</html>

Order Confirmation

curl -u 'username:password' 'https://listmonk.mysite.com/api/tx' \
  -H 'Content-Type: application/json' \
  -d '{
    "subscriber_mode": "fallback",
    "subscriber_emails": ["customer@example.com"],
    "template_id": 4,
    "data": {
      "order_id": "ORD-12345",
      "total": "$99.99",
      "items": [
        {"name": "Product A", "qty": 2, "price": "$49.99"},
        {"name": "Product B", "qty": 1, "price": "$50.00"}
      ]
    }
  }'
Template:
<!DOCTYPE html>
<html>
<body>
  <h1>Order Confirmation</h1>
  <p>Thank you for your order, {{ .Subscriber.Name }}!</p>
  <p>Order ID: <strong>{{ .Tx.Data.order_id }}</strong></p>
  
  <h2>Items:</h2>
  <ul>
    {{ range .Tx.Data.items }}
      <li>{{ .name }} - Qty: {{ .qty }} - {{ .price }}</li>
    {{ end }}
  </ul>
  
  <p><strong>Total: {{ .Tx.Data.total }}</strong></p>
</body>
</html>

Notification to Multiple Recipients

curl -u 'username:password' 'https://listmonk.mysite.com/api/tx' \
  -H 'Content-Type: application/json' \
  -d '{
    "subscriber_emails": [
      "admin1@example.com",
      "admin2@example.com",
      "manager@example.com"
    ],
    "template_id": 5,
    "subscriber_mode": "external",
    "data": {
      "alert_type": "High CPU Usage",
      "server": "web-01",
      "threshold": "90%",
      "timestamp": "2024-01-15 14:30:00"
    }
  }'

Send with File Attachments

For emails with file attachments, use multipart/form-data:
curl -u 'username:password' 'https://listmonk.mysite.com/api/tx' \
  -F 'data={
    "subscriber_emails": ["user@example.com"],
    "template_id": 6,
    "data": {"invoice_number": "INV-001"}
  }' \
  -F 'file=@invoice.pdf' \
  -F 'file=@receipt.pdf'

Request Format with Attachments

data
string
required
JSON string containing the standard transactional email parameters
file
file
File to attach (can be specified multiple times)

Template Variables

Transactional email templates have access to:

Subscriber Data

.Subscriber
object

Transaction Data

.Tx
object

Error Handling

Subscriber Not Found (Default Mode)

{
  "message": "subscriber not found: user@example.com"
}
Occurs when using default mode and the subscriber doesn’t exist in the database.

Invalid Template

{
  "message": "template not found: template 99"
}
Occurs when the specified template ID doesn’t exist.

Template Rendering Error

{
  "message": "error rendering template: undefined variable"
}
Occurs when the template references variables that weren’t provided in data.

Best Practices

1. Use Appropriate Subscriber Mode

  • Default: For application emails to registered users
  • Fallback: For emails that may go to both registered and unregistered users
  • External: For administrative notifications or external communications

2. Template Data Validation

Always provide all data that your template expects:
{
  "data": {
    "required_field": "value",
    "optional_field": "value"
  }
}
Use conditional checks in templates:
{{ if .Tx.Data.optional_field }}
  <p>{{ .Tx.Data.optional_field }}</p>
{{ end }}

3. Rate Limiting

Be mindful of sending limits. For bulk transactional emails, consider:
  • Batching requests
  • Implementing retry logic
  • Monitoring send rates

4. Error Handling

Implement proper error handling in your application:
import requests

response = requests.post(
    'https://listmonk.mysite.com/api/tx',
    auth=('username', 'password'),
    json={
        'subscriber_emails': ['user@example.com'],
        'template_id': 1,
        'data': {'key': 'value'}
    }
)

if response.status_code != 200:
    # Handle error
    print(f"Error: {response.json()['message']}")
else:
    print("Email sent successfully")

5. Testing

Always test transactional emails before production:
  1. Create test templates
  2. Use test email addresses
  3. Verify all template variables render correctly
  4. Test with missing/invalid data

Build docs developers (and LLMs) love