defmodule Swoosh.Adapters.Local.Storage.Memory do @moduledoc ~S""" In-memory storage driver used by the [Swoosh.Adapters.Local](Swoosh.Adapters.Local.html) module. The emails in this mailbox are stored in memory and won't persist once your application is stopped. """ use GenServer @doc """ Starts the server """ def start_link(args \\ []) do case GenServer.start_link(__MODULE__, args, name: {:global, __MODULE__}) do {:ok, pid} -> {:ok, pid} {:error, {:already_started, pid}} -> Process.link(pid) {:ok, pid} end end @doc """ Stops the server """ def stop() do GenServer.stop({:global, __MODULE__}) end @doc ~S""" Push a new email into the mailbox. In order to make it easy to fetch a single email, a `Message-ID` header is added to the email before being stored. ## Examples iex> email = new |> from("tony.stark@example.com") %Swoosh.Email{from: {"", "tony.stark@example.com"}, [...]} iex> Memory.push(email) %Swoosh.Email{from: {"", "tony.stark@example.com"}, headers: %{"Message-ID": "a1b2c3"}, [...]} """ def push(email) do GenServer.call({:global, __MODULE__}, {:push, email}) end @doc ~S""" Pop the last email from the mailbox. ## Examples iex> email = new |> from("tony.stark@example.com") %Swoosh.Email{from: {"", "tony.stark@example.com"}, [...]} iex> Memory.push(email) %Swoosh.Email{from: {"", "tony.stark@example.com"}, headers: %{"Message-ID": "a1b2c3"}, [...]} iex> Memory.all() |> Enum.count() 1 iex> Memory.pop() %Swoosh.Email{from: {"", "tony.stark@example.com"}, headers: %{"Message-ID": "a1b2c3"}, [...]} iex> Memory.all() |> Enun.count() 0 """ def pop() do GenServer.call({:global, __MODULE__}, :pop) end @doc ~S""" Get a specific email from the mailbox. ## Examples iex> email = new |> from("tony.stark@example.com") %Swoosh.Email{from: {"", "tony.stark@example.com"}, [...]} iex> Memory.push(email) %Swoosh.Email{from: {"", "tony.stark@example.com"}, headers: %{"Message-ID": "a1b2c3"}, [...]} iex> Memory.get("A1B2C3") %Swoosh.Email{from: {"", "tony.stark@example.com"}, headers: %{"Message-ID": "a1b2c3"}, [...]} """ def get(id) do GenServer.call({:global, __MODULE__}, {:get, id}) end @doc ~S""" List all the emails in the mailbox. ## Examples iex> email = new |> from("tony.stark@example.com") %Swoosh.Email{from: {"", "tony.stark@example.com"}, [...]} iex> Memory.push(email) %Swoosh.Email{from: {"", "tony.stark@example.com"}, headers: %{"Message-ID": "a1b2c3"}, [...]} iex> Memory.all() [%Swoosh.Email{from: {"", "tony.stark@example.com"}, headers: %{"Message-ID": "a1b2c3"}, [...]}] """ def all() do GenServer.call({:global, __MODULE__}, :all) end @doc ~S""" Delete all the emails currently in the mailbox. ## Examples iex> email = new |> from("tony.stark@example.com") %Swoosh.Email{from: {"", "tony.stark@example.com"}, [...]} iex> Memory.push(email) %Swoosh.Email{from: {"", "tony.stark@example.com"}, headers: %{"Message-ID": "a1b2c3"}, [...]} iex> Memory.delete_all() :ok iex> Memory.list() [] """ def delete_all() do GenServer.call({:global, __MODULE__}, :delete_all) end # Callbacks def init(_args) do {:ok, []} end def handle_call({:push, email}, _from, emails) do id = :crypto.strong_rand_bytes(16) |> Base.encode16() |> String.downcase() email = email |> Swoosh.Email.header("Message-ID", id) |> Swoosh.Email.put_private(:sent_at, DateTime.utc_now() |> DateTime.to_iso8601()) attachments_with_data = Enum.map(email.attachments, fn attachment -> %{attachment | data: Swoosh.Attachment.get_content(attachment)} end) email = %{email | attachments: attachments_with_data} {:reply, email, [email | emails]} end def handle_call(:pop, _from, [h | t]) do {:reply, h, t} end def handle_call({:get, id}, _from, emails) do email = Enum.find(emails, fn %{headers: %{"Message-ID" => msg_id}} -> msg_id == String.downcase(id) end) {:reply, email, emails} end def handle_call(:all, _from, emails) do {:reply, emails, emails} end def handle_call(:delete_all, _from, _emails) do {:reply, :ok, []} end end