unsent
unsent.dev
Get Started

Elixir

Send emails with the Unsent Elixir SDK

The Unsent Elixir SDK provides a simple and intuitive way to send transactional emails, manage contacts, campaigns, and domains from your Elixir applications.

Installation

Add unsent to your list of dependencies in mix.exs:

def deps do
  [
    {:unsent, "~> 1.0.2"}
  ]
end

Then run mix deps.get to install the package.

Quick Start

# Initialize the client
client = Unsent.new("un_your_api_key")

# Send an email
{:ok, email} = Unsent.Emails.send(client, %{
  to: "user@example.com",
  from: "hello@yourdomain.com",
  subject: "Welcome!",
  html: "<p>Welcome to our service!</p>"
})

Client Initialization

With API Key

client = Unsent.new("un_xxx")

Using Environment Variable

Set UNSENT_API_KEY environment variable and initialize without passing the key:

client = Unsent.new()

With Custom Options

client = Unsent.new("un_xxx", 
  base_url: "https://api.unsent.dev/v1", 
  raise_on_error: false  # Return tuples instead of raising
)

Sending Emails

Basic Email

{:ok, email} = Unsent.Emails.send(client, %{
  to: "recipient@example.com",
  from: "sender@yourdomain.com",
  subject: "Hello from Elixir",
  html: "<h1>Hello</h1><p>Email from Elixir SDK</p>",
  text: "Hello! Email from Elixir SDK"
})

Email with Attachments

Unsent.Emails.send(client, %{
  to: "user@example.com",
  from: "hello@company.com",
  subject: "Document Attached",
  html: "<p>Please find the document attached</p>",
  attachments: [
    %{
      filename: "invoice.pdf",
      content: "base64-encoded-content-here"
    }
  ]
})

Scheduled Email

# Schedule for 1 hour from now
scheduled_time = DateTime.utc_now() |> DateTime.add(3600, :second)

Unsent.Emails.send(client, %{
  to: "user@example.com",
  from: "hello@company.com",
  subject: "Scheduled Email",
  html: "<p>This email was scheduled</p>",
  scheduledAt: DateTime.to_iso8601(scheduled_time)
})

Batch Emails

Send up to 100 emails in a single API call:

emails = [
  %{
    to: "user1@example.com",
    from: "hello@company.com",
    subject: "Welcome User 1",
    html: "<p>Welcome!</p>"
  },
  %{
    to: "user2@example.com",
    from: "hello@company.com",
    subject: "Welcome User 2",
    html: "<p>Welcome!</p>"
  }
]

{:ok, result} = Unsent.Emails.batch(client, emails)

Idempotent Requests

Use idempotency keys to safely retry requests:

Unsent.Emails.send(client, payload, 
  headers: [{"Idempotency-Key", "unique-request-id-123"}]
)

Managing Emails

List Emails

# List all emails
{:ok, emails} = Unsent.Emails.list(client)

# With filters and pagination
Unsent.Emails.list(client,
  page: 1,
  limit: 50,
  startDate: "2024-01-01T00:00:00Z",
  endDate: "2024-12-31T23:59:59Z",
  domainId: "domain_id"
)

# Filter by multiple domains
Unsent.Emails.list(client, domainId: ["domain_1", "domain_2"])

Get Email

{:ok, email} = Unsent.Emails.get(client, "email_id")

Update Email

Unsent.Emails.update(client, "email_id", %{
  scheduledAt: "2024-12-01T10:00:00Z"
})

Cancel Email

Unsent.Emails.cancel(client, "email_id")

Email Events

# Get bounced emails
{:ok, bounces} = Unsent.Emails.get_bounces(client, page: 1, limit: 20)

# Get spam complaints
{:ok, complaints} = Unsent.Emails.get_complaints(client)

# Get unsubscribes
{:ok, unsubscribes} = Unsent.Emails.get_unsubscribes(client)

Contact Books & Contacts

Contact Books

# List contact books
{:ok, books} = Unsent.ContactBooks.list(client)

# Create contact book
{:ok, book} = Unsent.ContactBooks.create(client, %{
  name: "Newsletter Subscribers"
})

# Get contact book
{:ok, book} = Unsent.ContactBooks.get(client, book_id)

# Update contact book
Unsent.ContactBooks.update(client, book_id, %{name: "Updated Name"})

# Delete contact book
Unsent.ContactBooks.delete(client, book_id)

Contacts

# List contacts
{:ok, contacts} = Unsent.Contacts.list(client, book_id)

# With filters
Unsent.Contacts.list(client, book_id,
  page: 1,
  limit: 50,
  emails: "user1@example.com,user2@example.com"
)

# Create contact
{:ok, contact} = Unsent.Contacts.create(client, book_id, %{
  email: "user@example.com",
  firstName: "John",
  lastName: "Doe",
  data: %{plan: "premium", signupDate: "2024-01-01"}
})

# Get contact
{:ok, contact} = Unsent.Contacts.get(client, book_id, contact_id)

# Update contact
Unsent.Contacts.update(client, book_id, contact_id, %{
  firstName: "Jane"
})

# Upsert contact (create or update)
Unsent.Contacts.upsert(client, book_id, contact_id, %{
  email: "user@example.com",
  firstName: "John"
})

# Delete contact
Unsent.Contacts.delete(client, book_id, contact_id)

Campaigns

# List campaigns
{:ok, campaigns} = Unsent.Campaigns.list(client)

# Create campaign
{:ok, campaign} = Unsent.Campaigns.create(client, %{
  name: "Welcome Series",
  subject: "Welcome {{firstName}}!",
  html: "<h1>Hi {{firstName}}</h1><p>Welcome to {{company}}</p>",
  from: "hello@company.com",
  contactBookId: book_id
})

# Get campaign
{:ok, campaign} = Unsent.Campaigns.get(client, campaign_id)

# Schedule campaign
Unsent.Campaigns.schedule(client, campaign_id, %{
  scheduledAt: "2024-12-01T10:00:00Z"
})

# Pause campaign
Unsent.Campaigns.pause(client, campaign_id)

# Resume campaign
Unsent.Campaigns.resume(client, campaign_id)

Domains

# List domains
{:ok, domains} = Unsent.Domains.list(client)

# Create domain
{:ok, domain} = Unsent.Domains.create(client, %{
  name: "yourdomain.com",
  region: "us-east-1"
})

# Verify domain
Unsent.Domains.verify(client, domain_id)

# Get domain
{:ok, domain} = Unsent.Domains.get(client, domain_id)

# Delete domain
Unsent.Domains.delete(client, domain_id)

Templates

# List templates
{:ok, templates} = Unsent.Templates.list(client)

# Create template
{:ok, template} = Unsent.Templates.create(client, %{
  name: "Welcome Email",
  subject: "Welcome {{name}}!",
  html: "<h1>Hi {{name}}</h1><p>Welcome to {{company}}</p>"
})

# Get template
{:ok, template} = Unsent.Templates.get(client, template_id)

# Update template
Unsent.Templates.update(client, template_id, %{
  subject: "Updated: Welcome {{name}}!"
})

# Delete template
Unsent.Templates.delete(client, template_id)

# Use template in email
Unsent.Emails.send(client, %{
  to: "user@example.com",
  from: "hello@company.com",
  templateId: template_id,
  templateData: %{name: "John", company: "Acme Inc"}
})

Suppressions

Manage your suppression list to prevent emails from being sent to certain addresses:

# List all suppressions
{:ok, suppressions} = Unsent.Suppressions.list(client)

# With filters
Unsent.Suppressions.list(client,
  page: 1,
  limit: 50,
  search: "example.com",
  reason: "HARD_BOUNCE"  # or "COMPLAINT", "MANUAL", "UNSUBSCRIBE"
)

# Add to suppression list
Unsent.Suppressions.add(client, %{
  email: "blocked@example.com",
  reason: "MANUAL"
})

# Remove from suppression list
Unsent.Suppressions.delete(client, "blocked@example.com")

Analytics

Track your email performance and sender reputation:

# Get overall analytics
{:ok, analytics} = Unsent.Analytics.get(client)

# Get time series data
Unsent.Analytics.get_time_series(client, days: 30)
Unsent.Analytics.get_time_series(client, days: 7, domain: "yourdomain.com")

# Get reputation score
Unsent.Analytics.get_reputation(client)
Unsent.Analytics.get_reputation(client, domain: "yourdomain.com")

Settings

# Get team settings
{:ok, settings} = Unsent.Settings.get(client)

API Keys

# List API keys
{:ok, keys} = Unsent.ApiKeys.list(client)

# Create API key
{:ok, key} = Unsent.ApiKeys.create(client, %{
  name: "Production Key",
  permission: "FULL"  # or "SENDING"
})

# Delete API key
Unsent.ApiKeys.delete(client, key_id)

Error Handling

Exceptions (Default)

By default, the SDK raises exceptions on errors:

try do
  Unsent.Emails.send(client, invalid_payload)
rescue
  e in Unsent.HTTPError ->
    IO.puts("Error: #{e.error["message"]}")
    IO.puts("Status code: #{e.status_code}")
end

Result Tuples

Return {:ok, data} or {:error, reason} tuples instead:

client = Unsent.new("un_xxx", raise_on_error: false)

case Unsent.Emails.send(client, payload) do
  {:ok, email} -> 
    IO.puts("Email sent successfully!")
  {:error, error} -> 
    IO.puts("Failed to send: #{error["message"]}")
end

Advanced Features

Custom Headers

Unsent.Emails.send(client, payload, 
  headers: [
    {"Idempotency-Key", "unique-id"},
    {"X-Custom-Header", "value"}
  ]
)

Base URL Override

client = Unsent.new("un_xxx", base_url: "https://custom-api.unsent.dev/v1")

Resources

Next Steps