defimpl Poison.Encoder, for: Apostle.Mail do def encode %Apostle.Mail{}=mail, _opts do mail |> parse_mail |> Poison.encode! end defp parse_mail mail do mail |> take_attributes([:from, :name, :reply_to, :template_id, :layout_id, :headers]) |> stringify_values |> merge_data(mail.data) |> encode_attachments(mail.attachments) end defp take_attributes map, attrs do map |> Map.take(attrs) |> Enum.reduce(%{}, fn ({_k, nil}, r) -> r ({_k, ""}, r) -> r ({k, v}, r) when is_number(v) -> Map.put r, k, to_string(v) ({_k, v}, r) when is_map(v) and map_size(v) == 0 -> r ({k, v}, r) -> Map.put r, k, v end) end defp stringify_values map do map |> Enum.reduce %{}, fn ({_key, nil}, result) -> result ({key, %{}=value}, result)-> Map.put result, key, stringify_values(value) ({key, value}, result) -> Map.put result, key, to_string(value) end end defp merge_data(%{}=mail, %{}=d) when map_size(d) == 0 do mail end defp merge_data %{}=mail, %{}=data do Map.put mail, :data, data end defp encode_attachments(%{}=mail, %{}=a) when map_size(a) == 0 do mail end defp encode_attachments %{}=mail, %{}=attachments do attachments = Enum.reduce attachments, %{}, fn({name, content}, result)-> Map.put result, to_string(name), Base.encode64(content) end Map.put mail, :attachments, attachments end end