Skip to main content
This guide covers common patterns for sending transactional emails with Ark, from simple notifications to complex templates.
Building a white-label platform? You can send emails scoped to specific tenants using tenant_id. See the Architecture Overview for white-label sending patterns.

Basic Email

Send a simple email with HTML and plain text:
from ark import Ark

client = Ark()

email = client.emails.send(
    from_="hello@yourdomain.com",
    to=["user@example.com"],
    subject="Your order has shipped!",
    html="<h1>Order Shipped</h1><p>Your order #1234 is on its way.</p>",
    text="Order Shipped\n\nYour order #1234 is on its way."
)

print(f"Email sent: {email.data.id}")
Always include both html and text versions. Some email clients only display plain text, and it improves deliverability.

Multiple Recipients

Send to multiple recipients in a single request:
email = client.emails.send(
    from_="team@yourdomain.com",
    to=["user1@example.com", "user2@example.com"],
    cc=["manager@example.com"],
    bcc=["archive@yourdomain.com"],
    subject="Team Update",
    html="<p>Here is your weekly update...</p>"
)
Maximum 50 recipients per request. For larger sends, use the batch endpoint or make multiple requests.

Using Tags and Metadata

Add a tag and metadata to categorize and track emails:
email = client.emails.send(
    from_="orders@yourdomain.com",
    to=["customer@example.com"],
    subject="Order Confirmation #1234",
    html="<p>Thank you for your order!</p>",
    tag="order_confirmation",
    metadata={
        "order_id": "ord_1234",
        "customer_id": "cust_abc123",
        "campaign": "checkout_flow"
    }
)
Metadata in Webhooks: When you include metadata with an email, it’s automatically returned in all webhook events for that message (MessageSent, MessageBounced, etc.). This makes it easy to correlate delivery events with your internal systems.

Metadata Validation Rules

RuleLimit
Maximum keys10
Key length40 characters
Value length500 characters
Total size4KB
Key formatMust start with a letter, alphanumeric and underscores only
Metadata keys must match the pattern ^[a-zA-Z][a-zA-Z0-9_]*$. Keys like order-id (hyphen) or 123_key (starts with number) are invalid.

Attachments

Send files as attachments:
import base64

with open("invoice.pdf", "rb") as f:
    pdf_content = base64.b64encode(f.read()).decode()

email = client.emails.send(
    from_="billing@yourdomain.com",
    to=["customer@example.com"],
    subject="Your Invoice #INV-001",
    html="<p>Please find your invoice attached.</p>",
    attachments=[
        {
            "filename": "invoice.pdf",
            "content": pdf_content,
            "content_type": "application/pdf"
        }
    ]
)
Maximum attachment size is 25MB total. Large attachments may impact deliverability.

Custom Headers

Add custom email headers:
email = client.emails.send(
    from_="support@yourdomain.com",
    to=["customer@example.com"],
    subject="Re: Support Ticket #5678",
    html="<p>Thank you for contacting support...</p>",
    reply_to="support+5678@yourdomain.com",
    headers={
        "X-Ticket-ID": "5678",
        "References": "<original-message-id@example.com>",
        "In-Reply-To": "<original-message-id@example.com>"
    }
)

Controlling Tracking

Disable tracking for sensitive emails:
email = client.emails.send(
    from_="security@yourdomain.com",
    to=["user@example.com"],
    subject="Password Reset",
    html="<p>Click here to reset your password...</p>",
    track_opens=False,
    track_clicks=False
)

Error Handling

All SDKs provide typed exceptions for error handling:
import ark

try:
    email = client.emails.send(
        from_="hello@yourdomain.com",
        to=["user@example.com"],
        subject="Test",
        html="<p>Test</p>"
    )
    print(f"Email accepted: {email.data.id}")
except ark.BadRequestError as e:
    print(f"Invalid request: {e.message}")
except ark.RateLimitError as e:
    print(f"Rate limited - retry later")
except ark.APIError as e:
    print(f"API error: {e.message}")

Best Practices

Some email clients and spam filters prefer or require plain text versions.
Instead of just noreply@yourdomain.com, use "Your Company" <noreply@yourdomain.com>.
Longer subjects get truncated on mobile devices.
Send test emails to yourself to verify formatting across different clients.
Set up webhooks to receive bounce notifications and update your recipient list.

Next Steps