`https://lumail.io/api/v1/emails`

Send individual transactional emails directly to subscribers without creating a campaign. Perfect for welcome emails, password resets, order confirmations, and other automated communications.

> Sending to an address that is not already present creates a `TRANSACTIONAL` contact unless **Settings → Configuration → Add transactional recipients to the marketing list** is on. This endpoint is not a supported custom double-opt-in state machine; read [GDPR in Lumail](/docs/legal/gdpr-in-lumail#native-and-custom-double-opt-in) before using it for confirmation emails.

## Delivery Model and Priority

Lumail is API-first. For systems that support HTTP email hooks, call this endpoint from your hook handler. For tools that only support SMTP, use the [Lumail SMTP endpoint](/docs/api-reference/smtp), which accepts SMTP messages and queues them through the same transactional priority lane as this API.

For Supabase Auth email OTPs or magic links, use Supabase's **Send Email** hook when available. If the source can only use SMTP, follow the [SMTP transactional email tutorial](/docs/tutorials/smtp-transactional-emails) and configure `smtp.lumail.io` as the custom SMTP provider.

This endpoint, the SDK `emails.send()` method, the CLI `emails send` command, and the MCP/AI `send_email` tool use a dedicated QStash priority lane. Campaign and newsletter batches use a separate bulk lane, so a large newsletter send does not place OTP, password reset, or manually triggered transactional emails behind the campaign backlog.

The send is still asynchronous: a successful response means Lumail accepted and queued the email. End-to-end delivery depends on downstream provider and recipient mailbox behavior, but priority emails are dispatched through the priority lane as soon as priority-lane capacity is available.

## Request Body

| Field         | Type   | Required | Description                                                                      |
| ------------- | ------ | -------- | -------------------------------------------------------------------------------- |
| `to`          | string | Yes      | Email address to send the email to (subscriber will be created if doesn't exist) |
| `subject`     | string | Yes      | Email subject line                                                               |
| `content`     | string | Yes      | Email content (format depends on contentType)                                    |
| `contentType` | string | No       | Content format: `MARKDOWN` (default), `HTML`, or `TIPTAP`                        |
| `preview`     | string | No       | Email preview text shown in email clients                                        |
| `replyTo`     | string | No       | Reply-to email address (must be valid email format)                              |
| `from`        | string | Yes      | Sender email address (domain must be verified)                                   |
| `tracking`    | object | No       | Tracking options (see below)                                                     |

### Tracking Options

| Field            | Type    | Default | Description                                                       |
| ---------------- | ------- | ------- | ----------------------------------------------------------------- |
| `tracking.links` | boolean | `true`  | Enable link tracking (wraps links with tracking URLs)             |
| `tracking.open`  | boolean | `true`  | Enable open tracking (adds invisible pixel to detect email opens) |

Set `tracking.links: false` to keep original URLs without shortening or tracking. This is useful for transactional emails where you don't want links like `https://example.com/reset` to become `https://lumail.io/l/abc123`.

Open and click tracking can process personal data. For confirmation, authentication, and other necessary messages where tracking is not required, explicitly set both options to `false`.

### Subscriber creation and double opt-in

When `to` does not match an existing subscriber, Lumail creates one before queuing the email:

- By default the subscriber is created as `TRANSACTIONAL` (not marketing-eligible, still receives transactional mail).
- If **Add transactional recipients to the marketing list** is on, the subscriber is created as `SUBSCRIBED`. Double opt-in is ignored.
- Existing contacts keep their current status. Blocked addresses (`BANNED`, `BOUNCED`, `COMPLAINED`) are rejected.

The transactional API does not generate or expose the native Lumail confirmation token. Adding a tag after your own confirmation does not change Lumail's subscription status or populate `confirmedAt` and `confirmationIp`. Use the Subscribers API with Lumail's native double opt-in for the supported confirmation lifecycle, or manage consent and marketing eligibility entirely in your own system.

## Response

- **Success (200 OK)** - Email queued successfully for sending
- **Error (400 Bad Request)** - Invalid request data
- **Error (401 Unauthorized)** - Invalid or missing API token
- **Error (404 Not Found)** - Subscriber not found

## Response Fields

| Field             | Type    | Description                               |
| ----------------- | ------- | ----------------------------------------- |
| `success`         | boolean | Indicates if the operation was successful |
| `message`         | string  | Success message                           |
| `id`              | string  | Email ID (`eml_…`) used after the send is persisted |

## Content Types

Choose the format that best fits your use case:

| Type       | Description                                   | Best For                                 |
| ---------- | --------------------------------------------- | ---------------------------------------- |
| `MARKDOWN` | Plain text with Markdown formatting (default) | Simple emails, quick integration         |
| `HTML`     | Raw HTML content                              | Full design control, existing templates  |
| `TIPTAP`   | Tiptap JSON format (same as Lumail editor)    | Complex layouts, programmatic generation |

See detailed documentation for each format:

- [Send Email in Markdown](/docs/api-reference/api-emails-markdown)
- [Send Email in HTML](/docs/api-reference/api-emails-html)
- [Send Email in Tiptap](/docs/api-reference/api-emails-tiptap)

## Email Content Format

The `content` field uses Markdown format. You can include various elements:

### Basic Text

```markdown
Hello {{name}}, this is a basic email.
```

### Formatted Text

```markdown
This is **bold text** and this is _italic text_.
```

### Headings and Lists

```markdown
# Welcome {{name}}!

## Benefits

- First benefit
- Second benefit
- Third benefit

### Getting Started

1. Step one
2. Step two
3. Step three
```

### Links and Images

```markdown
Visit our [website](https://example.com) for more information.

![Company Logo](https://example.com/logo.png)
```

## Variable Substitution

You can use variables in your email content that will be automatically replaced with subscriber data:

- `{{name}}` - Subscriber's name
- `{{email}}` - Subscriber's email address
- `{{phone}}` - Subscriber's phone number
- `{{unsubscribeUrl}}` - Automatic unsubscribe link
- `{{customField}}` - Any custom field defined for the subscriber

## Domain Verification

The `from` email address domain must be verified in your account. The API will:

1. Extract the domain from the `from` email address
2. Verify the domain is authorized and verified for your organization
3. Reject the request if the domain is not verified

## Email Tracking

Transactional emails automatically include:

- **Open tracking** - Pixel tracking to detect email opens
- **Click tracking** - Link wrapping for click tracking
- **Unsubscribe links** - Automatic unsubscribe functionality
- **Email storage** - All sent emails are stored for analytics

## Rate Limiting

Emails are queued and sent at a controlled rate to ensure deliverability:

- Rate: 40 emails per second per delivery lane
- Parallelism: 40 concurrent sends per delivery lane
- Combined QStash dispatch: up to 80 emails per second when both priority and bulk lanes are saturated
- Priority queue: Transactional and manually triggered emails use the priority lane
- Bulk queue: Campaign, workflow campaign, and newsletter batches use the bulk lane
- Queue: Emails are processed through QStash for reliability

## Usage Examples

### Welcome Email

Perfect for onboarding new users:

```json
{
  "to": "newuser@example.com",
  "subject": "Welcome to {{companyName}}!",
  "content": "# Welcome {{name}}!\n\nThanks for joining us. Get started by exploring your dashboard.\n\n## Next Steps\n\n- Complete your profile\n- Explore our features\n- Join our community\n\nWe're excited to have you on board!",
  "from": "welcome@yourcompany.com",
  "preview": "Welcome to the platform"
}
```

### Order Confirmation

For e-commerce order confirmations:

```json
{
  "to": "customer@example.com",
  "subject": "Order Confirmation #{{orderNumber}}",
  "content": "## Thanks for your order, {{name}}!\n\nYour order #{{orderNumber}} has been confirmed and will be processed shortly.\n\n### Order Details\n\n- Order Number: {{orderNumber}}\n- Total: {{orderTotal}}\n- Shipping Address: {{shippingAddress}}\n\n**Estimated Delivery:** {{deliveryDate}}\n\nIf you have any questions, please don't hesitate to contact our support team.",
  "from": "orders@yourstore.com",
  "replyTo": "support@yourstore.com"
}
```

### Password Reset

For password reset notifications:

```json
{
  "to": "user@example.com",
  "subject": "Password Reset Request",
  "content": "Hi {{name}},\n\nYou requested a password reset for your account. Click the link below to reset your password:\n\n[Reset Password]({{resetUrl}})\n\n**This link will expire in 24 hours.**\n\nIf you didn't request this reset, please ignore this email or contact our support team if you have concerns.\n\nStay secure!",
  "from": "security@yourapp.com"
}
```

## Error Handling

Common error responses:

### Invalid Email Address

```json
{
  "message": "Invalid email format"
}
```

### Unauthorized Domain

```json
{
  "message": "Domain 'example.com' is not authorized or verified for this organization"
}
```

### Invalid Email Format

```json
{
  "message": "Invalid from email address"
}
```

### Validation Error

```json
{
  "message": "Validation failed",
  "errors": [
    {
      "field": "subject",
      "message": "Subject is required"
    }
  ]
}
```

## Related Documentation

- [Variables](/docs/features/variables) - Personalize emails with subscriber data
- [Content Deliverability Checker](/docs/features/content-deliverability) - Optimize emails before sending
- [Email Domains Setup](/docs/domains/email-domains) - Configure verified sending domains
- [API Tokens](/docs/api-reference/api-tokens) - Generate API tokens for authentication
- [Create Subscriber](/docs/api-reference/api-subscribers-post) - Add subscribers to send emails to


## API Reference
**Method:** POST
**Endpoint:** /api/v1/emails

### SDK
```ts
import { Lumail } from "lumail";
const lumail = new Lumail({ apiKey: "YOUR_API_TOKEN" });

const { id } = await lumail.emails.send({
  to: "user@example.com",
  from: "hello@yourdomain.com",
  subject: "Welcome to our platform!",
  content: "# Welcome {{name}}!\n\nHello {{name}}, welcome to our platform!",
  preview: "Welcome email preview",
});
console.log(id);
```

### cURL
```bash
curl -X POST https://lumail.io/api/v1/emails \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "user@example.com",
    "subject": "Welcome to our platform!",
    "content": "# Welcome {{name}}!\n\nHello {{name}}, welcome to our platform!",
    "preview": "Welcome email preview",
    "from": "hello@yourdomain.com"
  }'
```

### JavaScript
```javascript
const response = await fetch('https://lumail.io/api/v1/emails', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    to: 'user@example.com',
    subject: 'Welcome to our platform!',
    content: '# Welcome {{name}}!\n\nHello {{name}}, welcome to our platform!',
    preview: 'Welcome email preview',
    from: 'hello@yourdomain.com'
  })
});
const data = await response.json();
```

### Python
```python
import requests

url = "https://lumail.io/api/v1/emails"
headers = {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json"
}
payload = {
    "to": "user@example.com",
    "subject": "Welcome to our platform!",
    "content": "# Welcome {{name}}!\n\nHello {{name}}, welcome to our platform!",
    "preview": "Welcome email preview",
    "from": "hello@yourdomain.com"
}
response = requests.post(url, headers=headers, json=payload)
```

### Success Response
```json
{
  "success": true,
  "message": "Email queued for sending",
  "id": "eml_abc123def456"
}
```

### Error Response
```json
{
  "message": "Subscriber not found"
}
```
