Packages
swoosh
1.5.1
1.26.3
1.26.2
1.26.1
1.26.0
1.25.3
1.25.2
1.25.1
1.25.0
1.24.0
1.23.1
1.23.0
1.22.1
1.22.0
1.21.0
1.20.1
1.20.0
1.19.9
1.19.8
1.19.7
1.19.6
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.17.10
1.17.9
1.17.8
retired
1.17.7
retired
1.17.6
1.17.5
1.17.4
retired
1.17.3
1.17.2
1.17.1
1.17.0
1.16.12
1.16.11
1.16.10
1.16.9
1.16.8
1.16.7
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
retired
1.16.1
retired
1.16.0
1.15.3
1.15.2
1.15.1
1.15.0
1.14.4
1.14.3
1.14.2
1.14.1
1.14.0
1.13.0
1.12.0
1.11.6
1.11.5
1.11.4
1.11.3
1.11.2
1.11.1
retired
1.11.0
1.10.3
1.10.2
1.10.1
1.10.0
1.9.1
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.2
1.5.1
1.5.0
1.4.0
1.3.11
1.3.10
1.3.9
1.3.8
retired
1.3.7
1.3.6
retired
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.9
1.0.8
retired
1.0.7
retired
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.25.6
0.25.5
0.25.4
0.25.3
retired
0.25.2
0.25.1
0.25.0
0.24.4
0.24.3
0.24.2
0.24.1
0.24.0
0.23.5
0.23.4
0.23.3
0.23.2
0.23.1
0.23.0
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.1
0.16.0
0.15.0
0.14.0
0.13.0
0.12.1
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.1
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
Compose, deliver and test your emails easily in Elixir. Supports SMTP, Sendgrid, Mandrill, Postmark, Mailgun and many more out of the box. Preview your emails in the browser. Test your email sending code.
Current section
Files
Jump to
Current section
Files
lib/swoosh/adapters/gmail.ex
defmodule Swoosh.Adapters.Gmail do
@moduledoc """
An adapter that sends email using Gmail api
For reference: [Gmail API docs](https://developers.google.com/gmail/api)
## Dependency
Gmail adapter requires `Mail` dependency to format message as RFC 2822 message.
{:mail, ">= 0.0.0"}
Because `Mail` library removes Bcc headers, they are being added after email is
rendered, in adapter code.
## Example
# config/congig.exs
config :sample, Sample.Mailer
adapter: Swoosh.Adapters.Gmail,
access_token: {:system, GMAIL_API_ACCESS_TOKEN}
# To deal with token refresh, it could be a better idea to pass the access token
# in via deliver config explicitly, if you don't update the environment variable
# periodically. e.g.
MyMailer.deliver(my_email, access_token: my_access_token)
# lib/sample/mailer.ex
defmodule Sample.Mailer do
use Swoosh.Mailer, otp_app: :sample
end
## Required config parameters
- `:access_token` valid OAuth2 access token
Required scopes:
- gmail.compose
See https://developers.google.com/oauthplayground when developing
"""
use Swoosh.Adapter, required_config: [:access_token], required_deps: [mail: Mail]
alias Swoosh.Email
@base_url "https://www.googleapis.com/upload/gmail/v1"
@api_endpoint "/users/me/messages/send"
@impl true
def deliver(%Email{} = email, config) do
url = [base_url(config), @api_endpoint]
headers = [
{"Authorization", "Bearer #{config[:access_token]}"},
{"Content-Type", "message/rfc822"}
]
body = prepare_body(email)
case Swoosh.ApiClient.post(url, headers, body, email) do
{:ok, 200, _headers, body} ->
{:ok, parse_response(body)}
{:ok, code, _headers, body} when code >= 400 and code <= 599 ->
{:error, {code, parse_response(body)}}
{:error, reason} ->
{:error, reason}
end
end
defp parse_response(body) when is_binary(body),
do: body |> Swoosh.json_library().decode! |> parse_response()
defp parse_response(%{"id" => id, "threadId" => thread_id, "labelIds" => labels}) do
%{id: id, thread_id: thread_id, labels: labels}
end
defp parse_response(%{"error" => %{"errors" => errors, "code" => code, "message" => message}}) do
%{error: %{code: code, message: message}, errors: Enum.map(errors, &parse_error/1)}
end
defp parse_error(error) do
%{
domain: error["domain"],
reason: error["reason"],
message: error["message"],
location_type: error["locationType"],
location: error["location"]
}
end
defp base_url(config), do: config[:base_url] || @base_url
defp prepare_body(email) do
Mail.build_multipart()
|> prepare_from(email)
|> prepare_to(email)
|> prepare_cc(email)
|> prepare_bcc(email)
|> prepare_subject(email)
|> prepare_text(email)
|> prepare_html(email)
|> prepare_attachments(email)
|> prepare_reply_to(email)
|> prepare_custom_headers(email)
|> Mail.Renderers.RFC2822.render()
# When message is rendered, bcc header will be removed and we need to prepend bcc list to the
# beginning of the message. Gmail will handle it from there.
# https://github.com/DockYard/elixir-mail/blob/v0.2.0/lib/mail/renderers/rfc_2822.ex#L139
|> prepend_bcc(email)
end
defp prepare_from(body, %{from: nil}), do: body
defp prepare_from(body, %{from: from}), do: Mail.put_from(body, from)
defp prepare_to(body, %{to: []}), do: body
defp prepare_to(body, %{to: to}), do: Mail.put_to(body, to)
defp prepare_cc(body, %{cc: []}), do: body
defp prepare_cc(body, %{cc: cc}), do: Mail.put_cc(body, cc)
defp prepare_bcc(rendered_mail, %{bcc: []}), do: rendered_mail
defp prepare_bcc(rendered_mail, %{bcc: bcc}), do: Mail.put_bcc(rendered_mail, bcc)
defp prepend_bcc(rendered_message, %{bcc: []}), do: rendered_message
defp prepend_bcc(rendered_message, %{bcc: bcc}),
do: Mail.Renderers.RFC2822.render_header("bcc", bcc) <> "\r\n" <> rendered_message
defp prepare_subject(body, %{subject: subject}), do: Mail.put_subject(body, subject)
defp prepare_text(body, %{text_body: nil}), do: body
defp prepare_text(body, %{text_body: text_body}), do: Mail.put_text(body, text_body)
defp prepare_html(body, %{html_body: nil}), do: body
defp prepare_html(body, %{html_body: html_body}), do: Mail.put_html(body, html_body)
defp prepare_attachments(body, %{attachments: attachments}) do
Enum.reduce(attachments, body, &prepare_attachment/2)
end
defp prepare_attachment(attachment, body) do
Mail.put_attachment(body, {attachment.filename, Swoosh.Attachment.get_content(attachment)})
end
defp prepare_reply_to(body, %{reply_to: nil}), do: body
defp prepare_reply_to(body, %{reply_to: reply_to}), do: Mail.put_reply_to(body, reply_to)
defp prepare_custom_headers(body, %{headers: headers}) when headers == %{}, do: body
defp prepare_custom_headers(body, %{headers: headers}) do
Enum.reduce(headers, body, fn {key, value}, acc ->
Mail.Message.put_header(acc, key, value)
end)
end
end