Poodle Elixir SDK
View SourceElixir SDK for the Poodle email sending API.
Features
- 🚀 Simple and intuitive API
- 📧 HTML and plain text email support
- 🔒 Comprehensive error handling
- ⚡ Asynchronous email sending
- 🛡️ Built-in input validation
- 📊 Rate limiting support
- 🔧 Configurable via environment variables
- 🎯 Pattern-matchable error tuples
- 📖 Complete documentation and examples
- ✅ Elixir 1.14+ support
Installation
Add poodle
to your list of dependencies in mix.exs
:
def deps do
[
{:poodle, "~> 1.0"}
]
end
Then run:
mix deps.get
Quick Start
1. Set your API key
export POODLE_API_KEY=your_api_key_here
2. Send your first email
# Send an HTML email
{:ok, response} = Poodle.send_html(
"sender@yourdomain.com",
"recipient@example.com",
"Hello from Poodle!",
"<h1>Welcome!</h1><p>This is a test email.</p>"
)
IO.puts("Email sent! Message: #{response.message}")
Configuration
The SDK can be configured via environment variables or application config:
Environment Variables
export POODLE_API_KEY=your_api_key
export POODLE_BASE_URL=https://api.usepoodle.com
export POODLE_TIMEOUT=30000
export POODLE_DEBUG=false
Application Config
# config/config.exs
config :poodle,
api_key: "your_api_key",
base_url: "https://api.usepoodle.com",
timeout: 30_000,
debug: false
Usage Examples
Basic Email Sending
# HTML email
{:ok, response} = Poodle.send_html(
"sender@example.com",
"recipient@example.com",
"Welcome!",
"<h1>Hello World!</h1><p>Welcome to our service!</p>"
)
# Plain text email
{:ok, response} = Poodle.send_text(
"sender@example.com",
"recipient@example.com",
"Welcome!",
"Hello World! Welcome to our service!"
)
# Both HTML and text
{:ok, response} = Poodle.send(
"sender@example.com",
"recipient@example.com",
"Welcome!",
html: "<h1>Hello World!</h1>",
text: "Hello World!"
)
Using Email Structs
# Create an email struct
{:ok, email} = Poodle.Email.new(
"sender@example.com",
"recipient@example.com",
"Welcome!",
html: "<h1>Hello World!</h1>",
text: "Hello World!"
)
# Send the email
{:ok, response} = Poodle.send_email(email)
Asynchronous Sending
# Send email asynchronously
task = Poodle.send_async(
"sender@example.com",
"recipient@example.com",
"Welcome!",
html: "<h1>Hello World!</h1>"
)
# Wait for result
{:ok, response} = Task.await(task)
Error Handling
case Poodle.send_html(from, to, subject, html) do
{:ok, response} ->
IO.puts("Email sent! Message: #{response.message}")
# Check rate limit info
if response.rate_limit do
IO.puts("Rate limit remaining: #{response.rate_limit.remaining}")
end
{:error, %Poodle.Error{type: :unauthorized}} ->
IO.puts("Invalid API key")
{:error, %Poodle.Error{type: :rate_limit_exceeded, retry_after: retry_after}} ->
IO.puts("Rate limited. Retry after #{retry_after} seconds")
{:error, %Poodle.Error{type: :validation_error, message: message}} ->
IO.puts("Validation error: #{message}")
{:error, %Poodle.Error{type: :payment_required}} ->
IO.puts("Subscription expired or limit reached")
{:error, error} ->
IO.puts("Error: #{error.message}")
end
API Reference
Main Functions
Poodle.send/4
- Send email with HTML and/or text contentPoodle.send_html/5
- Send HTML emailPoodle.send_text/5
- Send plain text emailPoodle.send_email/3
- Send email using Email structPoodle.send_async/4
- Send email asynchronouslyPoodle.validate_config/1
- Validate configuration
Data Structures
Email Struct
%Poodle.Email{
from: "sender@example.com",
to: "recipient@example.com",
subject: "Email Subject",
html: "<h1>HTML content</h1>", # optional
text: "Plain text content" # optional
}
Response Struct
%Poodle.Response{
success: true,
message: "Email queued for sending",
rate_limit: %Poodle.RateLimit{
limit: 2,
remaining: 1,
reset: 1640995200
}
}
Error Struct
%Poodle.Error{
type: :rate_limit_exceeded,
message: "Rate limit exceeded",
status_code: 429,
retry_after: 30,
details: %{...}
}
Error Types
The SDK provides specific error types for different scenarios:
:validation_error
- Invalid input data:unauthorized
- Invalid or missing API key:forbidden
- Account suspended:payment_required
- Subscription issues:rate_limit_exceeded
- Rate limit exceeded:server_error
- Server-side errors:network_error
- Network connectivity issues:timeout
- Request timeout:dns_error
- DNS resolution failed:ssl_error
- SSL/TLS errors
Phoenix Integration
In a Phoenix Controller
defmodule MyAppWeb.EmailController do
use MyAppWeb, :controller
def send_welcome(conn, %{"email" => email, "name" => name}) do
case Poodle.send_html(
"welcome@myapp.com",
email,
"Welcome, #{name}!",
render_welcome_email(name)
) do
{:ok, _response} ->
json(conn, %{success: true, message: "Welcome email sent"})
{:error, error} ->
conn
|> put_status(:unprocessable_entity)
|> json(%{success: false, error: error.message})
end
end
defp render_welcome_email(name) do
"""
<h1>Welcome, #{name}!</h1>
<p>Thank you for joining our service.</p>
"""
end
end
Background Jobs with Oban
defmodule MyApp.Workers.EmailWorker do
use Oban.Worker, queue: :emails
@impl Oban.Worker
def perform(%Oban.Job{args: %{"type" => "welcome", "email" => email, "name" => name}}) do
case Poodle.send_html(
"welcome@myapp.com",
email,
"Welcome, #{name}!",
render_welcome_email(name)
) do
{:ok, _response} -> :ok
{:error, _error} -> {:error, "Failed to send email"}
end
end
defp render_welcome_email(name) do
"""
<h1>Welcome, #{name}!</h1>
<p>Thank you for joining our service.</p>
"""
end
end
Development
Running Tests
# Set test environment variables
export POODLE_API_KEY=test_api_key
# Run tests
mix test
# Run tests with coverage
mix test --cover
Code Quality
# Format code
mix format
# Run Credo
mix credo
# Run Dialyzer
mix dialyzer
Contributing
Contributions are welcome! Please read our Contributing Guide for details on the process for submitting pull requests and our Code of Conduct.
License
This project is licensed under the MIT License - see the LICENSE file for details.