# Unsent Elixir SDK
Official Elixir SDK for the [Unsent API](https://unsent.dev) - Send transactional emails with ease.
## Prerequisites
- [Unsent API key](https://app.unsent.dev/dev-settings/api-keys)
- [Verified domain](https://app.unsent.dev/domains)
- Elixir 1.14 or higher
## Installation
Add `unsent` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:unsent, "~> 1.0.1"}
]
end
```
## Usage
### Basic Setup
```elixir
client = Unsent.new("us_12345")
```
### Environment Variables
You can also set your API key using environment variables:
```elixir
# Set UNSENT_API_KEY in your environment
# Then initialize without passing the key
client = Unsent.new()
```
### Sending Emails
#### Simple Email
```elixir
{:ok, data} = Unsent.Emails.send(client, %{
to: "hello@acme.com",
from: "hello@company.com",
subject: "Unsent email",
html: "<p>Unsent is the best email service provider to send emails</p>",
text: "Unsent is the best email service provider to send emails"
})
IO.inspect(data, label: "Email sent")
```
#### Email with Attachments
```elixir
{:ok, data} = Unsent.Emails.send(client, %{
to: "hello@acme.com",
from: "hello@company.com",
subject: "Email with attachment",
html: "<p>Please find the attachment below</p>",
attachments: [
%{
filename: "document.pdf",
content: "base64-encoded-content-here"
}
]
})
```
#### Scheduled Email
```elixir
scheduled_time = DateTime.utc_now() |> DateTime.add(1, :hour)
{:ok, data} = Unsent.Emails.send(client, %{
to: "hello@acme.com",
from: "hello@company.com",
subject: "Scheduled email",
html: "<p>This email was scheduled</p>",
scheduledAt: scheduled_time
})
```
#### Batch Emails
```elixir
emails = [
%{
to: "user1@example.com",
from: "hello@company.com",
subject: "Hello User 1",
html: "<p>Welcome User 1</p>"
},
%{
to: "user2@example.com",
from: "hello@company.com",
subject: "Hello User 2",
html: "<p>Welcome User 2</p>"
}
]
{:ok, data} = Unsent.Emails.batch(client, emails)
IO.puts("Sent #{length(data["data"])} emails")
```
#### Idempotent Retries
```elixir
# Idempotent retries: same payload + same key returns the original response
payload = %{
to: "hello@acme.com",
from: "hello@company.com",
subject: "Welcome!",
html: "<p>Welcome to our service</p>"
}
{:ok, data} = Unsent.Emails.send(
client,
payload,
headers: [{"Idempotency-Key", "signup-123"}]
)
# Works for batch requests as well
batch_payload = [
# ... items
]
{:ok, data} = Unsent.Emails.batch(
client,
batch_payload,
headers: [{"Idempotency-Key", "bulk-welcome-1"}]
)
# If the same key is reused with a different payload, the API responds with HTTP 409.
```
### Managing Emails
#### Get Email Details
```elixir
{:ok, email} = Unsent.Emails.get(client, "email_id")
IO.puts("Email status: #{email["status"]}")
```
#### Update Email
```elixir
{:ok, data} = Unsent.Emails.update(client, "email_id", %{
subject: "Updated subject",
html: "<p>Updated content</p>"
})
```
#### Cancel Scheduled Email
```elixir
{:ok, _} = Unsent.Emails.cancel(client, "email_id")
IO.puts("Email cancelled successfully")
```
### Managing Contacts
#### Create Contact
```elixir
{:ok, contact} = Unsent.Contacts.create(client, "contact_book_id", %{
email: "user@example.com",
firstName: "John",
lastName: "Doe",
metadata: %{
company: "Acme Inc",
role: "Developer"
}
})
```
#### Get Contact
```elixir
{:ok, contact} = Unsent.Contacts.get(client, "contact_book_id", "contact_id")
```
#### Update Contact
```elixir
{:ok, contact} = Unsent.Contacts.update(client, "contact_book_id", "contact_id", %{
firstName: "Jane",
metadata: %{
role: "Senior Developer"
}
})
```
#### Upsert Contact
```elixir
# Creates if doesn't exist, updates if exists
{:ok, contact} = Unsent.Contacts.upsert(client, "contact_book_id", "contact_id", %{
email: "user@example.com",
firstName: "John",
lastName: "Doe"
})
```
#### Delete Contact
```elixir
{:ok, _} = Unsent.Contacts.delete(client, "contact_book_id", "contact_id")
```
### Managing Campaigns
#### Create Campaign
```elixir
{:ok, campaign} = Unsent.Campaigns.create(client, %{
name: "Welcome Series",
subject: "Welcome to our service!",
html: "<p>Thanks for joining us!</p>",
from: "welcome@example.com",
contactBookId: "cb_1234567890"
})
IO.puts("Campaign created! ID: #{campaign["id"]}")
```
#### Schedule Campaign
```elixir
{:ok, _} = Unsent.Campaigns.schedule(client, campaign["id"], %{
scheduledAt: "2024-12-01T10:00:00Z"
})
```
#### Pause/Resume Campaigns
```elixir
# Pause a campaign
{:ok, _} = Unsent.Campaigns.pause(client, "campaign_123")
# Resume a campaign
{:ok, _} = Unsent.Campaigns.resume(client, "campaign_123")
```
#### Get Campaign Details
```elixir
{:ok, campaign} = Unsent.Campaigns.get(client, "campaign_id")
IO.puts("Campaign status: #{campaign["status"]}")
```
### Managing Domains
#### List Domains
```elixir
{:ok, domains} = Unsent.Domains.list(client)
Enum.each(domains, fn domain ->
IO.puts("Domain: #{domain["domain"]}, Status: #{domain["status"]}")
end)
```
#### Create Domain
```elixir
{:ok, domain} = Unsent.Domains.create(client, %{
domain: "example.com"
})
```
#### Verify Domain
```elixir
{:ok, result} = Unsent.Domains.verify(client, 123)
IO.puts("Verification status: #{result["status"]}")
```
#### Get Domain
```elixir
{:ok, domain} = Unsent.Domains.get(client, 123)
```
## Error Handling
The SDK returns `{:ok, data}` on success and `{:error, error}` on failure.
```elixir
case Unsent.Emails.send(client, payload) do
{:ok, data} ->
IO.puts("Success: #{data["id"]}")
{:error, error} ->
IO.puts("Error: #{error.message}")
end
```
## License
MIT
## Support
- [Documentation](https://docs.unsent.dev)
- [GitHub Issues](https://github.com/souravsspace/unsent-elixir/issues)
- [Discord Community](https://discord.gg/unsent)