Back to posts
Building a Robust Email API with Phoenix and Amazon SES

Building a Robust Email API with Phoenix and Amazon SES

Juma Baraka / March 5, 2025

In the world of web development, sending emails programmatically is a crucial feature for many applications. As an Elixir and Phoenix developer, I recently created a reliable email API using Phoenix and Amazon Simple Email Service (SES). This blog post walks through my implementation, highlighting the power and elegance of Elixir for building scalable backend services.

Why Phoenix and Amazon SES?

Choosing the right technology stack is critical for any project. I opted for:

  • Phoenix: A powerful Elixir web framework known for its performance and reliability
  • Amazon SES: A cost-effective, scalable email sending service
  • Elixir: A functional programming language that excels in concurrent and distributed systems

Technical Implementation

Dependencies

First, I added the necessary dependencies to my mix.exs:

def deps do
  [
    {:swoosh, "~> 1.8"}      # Email library for Elixir
    {:gen_smtp, "~> 1.0"}
  ]
end

Configuration

defmodule YourApp.Mailer do
  use Swoosh.Mailer, otp_app: :your_app
end

Configuring Amazon SES required careful management of credentials:

# config/config.exs
config :your_app, YourApp.Mailer,
  adapter: Swoosh.Adapters.AmazonSES,
  region: "us-east-1",
  access_key: System.get_env("AWS_ACCESS_KEY_ID"),
  secret: System.get_env("AWS_SECRET_ACCESS_KEY")

Email Context Module

I created a dedicated context module to handle email-related logic:

defmodule YourApp.Email do
  import Swoosh.Email

  def welcome_email(user) do
    new()
    |> to({user.name, user.email})
    |> from("alerts@yourapp.net")
    |> subject("Welcome to Your App")
    |> html_body("<h1>Welcome to Your App!</h1><p>We're excited to have you on board!</p>")
    |> text_body("Welcome to Your App! We're excited to have you on board!")
  end

  def notification_email(recipient, subject, body) do
    new()
    |> to(recipient)
    |> from("YourApp Support <alerts@yourapp.net>")
    |> subject(subject)
    |> html_body(body)
    |> text_body(String.replace(body, ~r/<[^>]*>/, ""))
  end
end

Phoenix Controller Integration

Integrating the email sending into a Phoenix controller:

defmodule YourAppWeb.EmailController do
  use YourAppWeb, :controller

  alias YourApp.Email
  alias YourApp.Mailer

  def send(conn, email_params) do
    with {:ok, _result} <- send_email(email_params) do
      conn
      |> put_status(:ok)
      |> json(%{status: "success", message: "Email sent successfully"})
    else
      {:error, reason} ->
        conn
        |> put_status(:bad_request)
        |> json(%{status: "error", message: reason})
    end
  end

  defp send_email(%{to: to, subject: subject, body: body}) do
    try do
      packet = Email.notification_email(to, subject, body)
      result = packet |> Mailer.deliver()

      case result do
        {:ok, _} ->
          {:ok, "Email sent successfully"}

        {:error, reason} ->
          {:error, "Failed to send email: #{inspect(reason)}"}
      end
    rescue
      e ->
        {:error, "Exception while sending email: #{inspect(e)}"}
    end
  end
end

Performance Considerations

Elixir's concurrency model shines when handling email sending:

  • Lightweight processes allow for async email dispatching
  • Built-in fault tolerance prevents system-wide failures
  • Easy to scale horizontally

Security Measures

  • Use environment variables for AWS credentials
  • Implement rate limiting
  • Add logging for tracking email events
  • Use secure email templates

Lessons Learned

  1. Always handle potential failures in email sending
  2. Use environment-specific configurations
  3. Leverage Elixir's pattern matching for clean code
  4. Implement proper error tracking and logging

Conclusion

Building an email API with Phoenix and Amazon SES showcases the power of Elixir for creating robust, scalable backend services. The combination of functional programming principles and powerful libraries makes complex tasks like email sending straightforward and reliable.

About the Developer

I'm a passionate Elixir and Phoenix developer with a focus on building scalable, maintainable backend systems. This project demonstrates my ability to:

  • Integrate third-party services
  • Write clean, functional code
  • Handle complex scenarios with elegant solutions

Looking for an Elixir developer? Let's connect!


Technologies Used:

  • Elixir
  • Phoenix Framework
  • Amazon SES
  • Swoosh