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, 
  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)

# Get events for a specific email
{:ok, events} = Unsent.Emails.get_events(client, "email_id")
{:ok, events} = Unsent.Emails.get_events(client, "email_id", page: 1, limit: 20)

Webhooks

Manage webhooks to receive real-time notifications about email events:

# List webhooks
{:ok, webhooks} = Unsent.Webhooks.list(client)

# Create webhook
{:ok, webhook} = Unsent.Webhooks.create(client, %{
  url: "https://example.com/webhooks",
  eventTypes: ["email.sent", "email.delivered", "email.bounced"]
})

# Get webhook
{:ok, webhook} = Unsent.Webhooks.get(client, webhook_id)

# Update webhook
Unsent.Webhooks.update(client, webhook_id, %{
  url: "https://example.com/updated-webhook"
})

# Test webhook
Unsent.Webhooks.test(client, webhook_id)

# Delete webhook
Unsent.Webhooks.delete(client, webhook_id)

Activity & Events

Activity Feed

Get recent activity for your account:

# Get activity feed
{:ok, activity} = Unsent.Activity.get(client)

# With pagination
Unsent.Activity.get(client, page: 1, limit: 50)

Events

List all events across your account:

# List events
{:ok, events} = Unsent.Events.list(client)

# With filters
Unsent.Events.list(client,
  page: 1,
  limit: 100,
  type: "email.delivered"
)

Metrics & Stats

Metrics

Get detailed metrics for your account:

# Get metrics
{:ok, metrics} = Unsent.Metrics.get(client)

# With period filter
Unsent.Metrics.get(client, period: "month")

Stats

Get aggregated statistics:

# Get stats
{:ok, stats} = Unsent.Stats.get(client)

System & Teams

System Operations

Check API health and version:

# Health check
{:ok, health} = Unsent.System.health(client)

# Get API version
{:ok, version} = Unsent.System.version(client)

Teams

Manage team information:

# Get current team
{:ok, team} = Unsent.Teams.get(client)

# List all teams
{:ok, teams} = Unsent.Teams.list(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 (must include unsubscribe link)
{:ok, campaign} = Unsent.Campaigns.create(client, %{
  name: "Welcome Series",
  subject: "Welcome {{firstName}}!",
  html: "<h1>Hi {{firstName}}</h1><p>Welcome to {{company}}</p><p><a href='{{unsent_unsubscribe_url}}'>Unsubscribe</a></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)

Note: Campaign HTML must include the {{unsent_unsubscribe_url}} placeholder for compliance.

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)

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

# Get domain stats
{:ok, stats} = Unsent.Domains.get_stats(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)

Provider Connections

Manage email provider connections (Amazon SES, SendGrid) for your team. Each connection stores encrypted credentials used by domains to route emails.

List Provider Connections

Get all configured provider connections:

{:ok, connections} = Unsent.ProviderConnections.list(client)

Enum.each(connections, fn conn ->
  IO.puts("#{conn["name"]}: #{conn["provider"]}")
end)

Create Provider Connection

Amazon SES

{:ok, connection} = Unsent.ProviderConnections.create(client, %{
  provider: "ses",
  name: "Production SES",
  credentials: %{
    accessKeyId: "AKIA...",
    secretAccessKey: "...",
    region: "us-east-1"
  }
})

IO.puts("Provider connection created: #{connection["id"]}")

SendGrid

{:ok, connection} = Unsent.ProviderConnections.create(client, %{
  provider: "sendgrid",
  name: "Marketing SendGrid",
  credentials: %{
    apiKey: "SG...."
  }
})

Delete Provider Connection

Remove a provider connection by ID:

{:ok, _} = Unsent.ProviderConnections.delete(client, "conn_abc123")

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

On this page