Skip to content

Commit

Permalink
Merge pull request #15 from cciuenf/feature/mailer
Browse files Browse the repository at this point in the history
feature/mailer
  • Loading branch information
Matheus de Souza Pessanha authored Aug 2, 2021
2 parents 6528fbe + 79de8e8 commit 3b17ecb
Show file tree
Hide file tree
Showing 14 changed files with 608 additions and 2 deletions.
21 changes: 21 additions & 0 deletions .env-sample
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
# ---------------------------#
# Sentry
# ---------------------------#
SENTRY_DNS=
SENTRY_ENV=

# ---------------------------#
# Oban
# ---------------------------#
START_BAN_JOBS=

# ---------------------------#
# Google Cloud
# ---------------------------#
GCP_CLIENT_ID=
GCP_CLIENT_SECRET=

# ---------------------------#
# Mailer
# ---------------------------#
MAILSERVICE=
MAIL_SERVER=
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_PORT=
42 changes: 42 additions & 0 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,48 @@ docker-compose run --rm fuschia mix ecto.setup

-----

** Aplicações

Esse projeto está dividio em diversas sub-aplicações que possuem diferentes responsabilidades.

#+begin_example

#+end_example

*** Fuschia.Mailer

Responsável pelo processamento e envio/disparo dos emails. Estamos utilizando o [[Swoosh][https://github.com/swoosh/swoosh]].

Para testar o preview de email, siga a seguinte documentação:

**** Variáveis de ambiente
Necessárias em produção:
- =MAIL_SERVER=: Server do smtp (default: =smtp.gmail.com=)
- =MAIL_USERNAME=: User do smtp (default: [email protected]=)
- =MAIL_PASSWORD=: Senha do smtp
- =MAIL_PORT=: Porta do smtp (default: =587=)
- =MAIL_SERVICE=: O serviço de email a ser usado. Pode ser =gmail= ou =local=.
(default prod: =gmail=, default dev: =local=)

*Observação*: Em ambiente de desenvolvimento, toda vez que a variável de ambiente =MAIL_SERVICE= é alterada
para trocar o adapter, toda a aplicação deve ser compilada usando

#+begin_src sh
mix compile --force
#+end_src

**** Rodando localmente
Essa aplicação também conta com um servidor para visualizar os emails enviados usando o adaptador local,
basta entrar na aplicação/container e utilizar:

#+begin_src sh
iex -S mix swoosh.mailbox.server
#+end_src

Que um servidor no local https://127.0.0.1:4001 vai apresentar uma página web listando os emails
enviados localmente através do `iex` que ficou aberto com o comando anterior.

-----

** Rodando os testes

Expand Down
29 changes: 28 additions & 1 deletion config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,37 @@ config :sentry,
# ---------------------------#
config :fuschia, Oban,
repo: Fuschia.Repo,
queues: [mailers: 5]
queues: [mailer: 5]

config :fuschia, :jobs, start: System.get_env("START_OBAN_JOBS", "true")

# ---------------------------#
# Mailer
# ---------------------------#
adapter =
case System.get_env("MAIL_SERVICE", "local") do
"gmail" -> Swoosh.Adapters.SMTP
_ -> Swoosh.Adapters.Local
end

if adapter == Swoosh.Adapters.Local do
config :swoosh, serve_mailbox: true, preview_port: 4001
end

config :fuschia, Fuschia.Mailer,
adapter: adapter,
relay: System.get_env("MAIL_SERVER", "smtp.gmail.com"),
username: System.get_env("MAIL_USERNAME", "[email protected]"),
password: System.get_env("MAIL_PASSWORD", ""),
ssl: false,
tls: :always,
auth: :always,
port: System.get_env("MAIL_PORT", "587")

config :fuschia, :pea_pescarte_contact,
notifications_mail: "[email protected]",
telephone: " 0800 026 2828"

# ---------------------------#
# Timex
# ---------------------------#
Expand Down
46 changes: 46 additions & 0 deletions lib/fuschia/jobs/mailer_job.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
defmodule Fuschia.Jobs.MailerJob do
@moduledoc false

use Oban.Worker, queue: :mailer, max_attempts: 4

require Logger

alias Fuschia.{Mailer, Parser}

@doc """
Deliver an email to partner
Example:
iex> %{
to: "[email protected]",
subject: "some subject",
layout: "notificacao",
template: "nova_midia",
assigns: %{user_cpf: "999.999.999-99"}
}
|> Fuschia.Jobs.MailerJob.new()
|> Oban.insert!()
"""
@impl Oban.Worker
def perform(%{args: args}) do
Logger.info("==> [MailerJob] Sending email...")

Mailer.new_email(
args["to"],
args["subject"],
args["layout"],
args["template"],
Parser.atomize_map(args["assigns"]),
args["base"],
args["bcc"]
)
|> Mailer.deliver!()

Logger.info("==> [MailerJob] Sent email")

:ok
rescue
error ->
Logger.error(Exception.format(:error, error, __STACKTRACE__))
{:error, error}
end
end
48 changes: 48 additions & 0 deletions lib/fuschia/mailer.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
defmodule Fuschia.Mailer do
@moduledoc """
Mailer public API
"""

use Swoosh.Mailer, otp_app: :fuschia

alias Fuschia.Mailer.HTML
alias Swoosh.Email

@doc """
Returns an email structure populated with a `recipient` and a
`subject` and assembles the email's html body based on the given
templates `layout` and `email` and given `assigns`.
"""
@spec new_email(
String.t() | {String.t(), String.t()} | [String.t()] | [{String.t(), String.t()}],
String.t(),
String.t(),
String.t(),
map,
String.t(),
String.t() | {String.t(), String.t()} | [String.t()] | [{String.t(), String.t()}] | []
) :: Email.t()
def new_email(recipient, subject, layout, template, assigns \\ %{}, base \\ "base", bcc \\ [])
when is_map(assigns) do
body = HTML.assemble_body(layout, template, assigns, base)

Email.new()
|> Email.to(recipient)
|> Email.bcc(bcc)
|> Email.from({"Plataforma PEA Pescarte", notifications_mail()})
|> Email.subject("[Plataforma PEA Pescarte] #{subject}")
|> Email.html_body(body)
end

@doc """
Add a new attachment to the email.
"""
@spec add_attachment(Email.t(), String.t()) :: Email.t()
def add_attachment(%Email{} = struct, file) when is_binary(file) do
Email.attachment(struct, file)
end

defp notifications_mail do
Application.get_env(:fuschia, :pea_pescarte_contact)[:notifications_mail]
end
end
48 changes: 48 additions & 0 deletions lib/fuschia/mailer/html.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
defmodule Fuschia.Mailer.HTML do
@moduledoc false

@doc """
Inject the `assigns` values into the `email` template's .eex tags
from the "homologacao" or "financiamento" `project` and then render
the resulting HTML page into a base template.
Returns an HTML page in string format.
"""
@spec assemble_body(String.t(), String.t(), map) :: any
def assemble_body(project, email, assigns, base \\ "base") when is_map(assigns) do
assigns
|> rewrite_name()
|> rewrite_email_address()
|> render_email(project, email)
|> render_layout(base)
end

def templates_path, do: "#{:code.priv_dir(:fuschia)}/templates"

defp pea_pescarte_contact do
:fuschia
|> Application.get_env(:pea_pescarte_contact)
|> Map.new()
end

defp rewrite_name(%{user_nome_completo: name} = assigns), do: Map.put(assigns, :nome, name)
defp rewrite_name(%{nome: name} = assigns), do: Map.put(assigns, :nome, name)
defp rewrite_name(assigns), do: Map.put(assigns, :nome, "")

defp rewrite_email_address(%{email: email} = assigns), do: Map.put(assigns, :email, email)
defp rewrite_email_address(assigns), do: Map.put(assigns, :email, "")

defp render_email(assigns, project, email) do
EEx.eval_file("#{templates_path()}/email/#{project}/#{email}.html.eex",
assigns: assigns,
pea_pescarte: pea_pescarte_contact()
)
end

defp render_layout(inner_content, nil), do: render_layout(inner_content, "base")

defp render_layout(inner_content, base) do
EEx.eval_file("#{templates_path()}/layout/#{base}.html.eex",
assigns: [inner_content: inner_content]
)
end
end
2 changes: 2 additions & 0 deletions lib/fuschia/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ defmodule Fuschia.Parser do
|> Map.new()
end

def atomize_map(value), do: value

@doc ~S"""
Converts an antom map to a string map
Expand Down
2 changes: 1 addition & 1 deletion lib/fuschia_web/swagger/schemas/auth.ex
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ defmodule FuschiaWeb.Swagger.AuthSchemas do
"user" => %{
"dataNasc" => "2021-07-27",
"cpf" => "999.999.999-99",
"email" => "teste@solfacil.com.br",
"email" => "teste@pescarte.com.br",
"nomeCompleto" => "Joãozinho Testinho",
"perfil" => "pesquisador",
"permissoes" => %{
Expand Down
2 changes: 2 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ defmodule Fuschia.MixProject do
[
{:phoenix, "~> 1.5.9"},
{:phoenix_ecto, "~> 4.1"},
{:swoosh, "~> 1.4"},
{:mail, ">= 0.0.0"},
{:bcrypt_elixir, "~> 2.0"},
{:paginator, "~> 1.0.3"},
{:ecto_sql, "~> 3.4"},
Expand Down
2 changes: 2 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
"jose": {:hex, :jose, "1.11.1", "59da64010c69aad6cde2f5b9248b896b84472e99bd18f246085b7b9fe435dcdb", [:mix, :rebar3], [], "hexpm", "078f6c9fb3cd2f4cfafc972c814261a7d1e8d2b3685c0a76eb87e158efff1ac5"},
"mail": {:hex, :mail, "0.2.3", "2c6bb5f8a5f74845fa50ecd0fb45ea16b164026f285f45104f1c4c078cd616d4", [:mix], [], "hexpm", "932b398fa9c69fdf290d7ff63175826e0f1e24414d5b0763bb00a2acfc6c6bf5"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
Expand All @@ -50,6 +51,7 @@
"recase": {:hex, :recase, "0.7.0", "3f2f719f0886c7a3b7fe469058ec539cb7bbe0023604ae3bce920e186305e5ae", [:mix], [], "hexpm", "36f5756a9f552f4a94b54a695870e32f4e72d5fad9c25e61bc4a3151c08a4e0c"},
"sentry": {:hex, :sentry, "8.0.5", "5ca922b9238a50c7258b52f47364b2d545beda5e436c7a43965b34577f1ef61f", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 2.3", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "4972839fdbf52e886d7b3e694c8adf421f764f2fa79036b88fb4742049bd4b7c"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"swoosh": {:hex, :swoosh, "1.5.0", "2be4cfc1be10f2203d1854c85b18d8c7be0321445a782efd53ef0b2b88f03ce4", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b53891359e3ddca263ece784051243de84c9244c421a0dee1bff1d52fc5ca420"},
"telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},
Expand Down
24 changes: 24 additions & 0 deletions priv/templates/email/user/confirmation.html.eex
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<p>Olá, <strong><%= @nome %></strong>!</p>
<p>Você recebeu um convite para se cadastrar na plataforma PEA Pescarte!</p>
<p>Ao clicar no link abaixo, você irá se cadastrar como pesquisador!</p>
<a
href="<%= @link %>"
title="CONFIRMAR CADASTRO"
style="
display: inline-block;
text-align: center;
height: 40px;
background: #0E4771;
border-radius: 4px;
text-decoration: none;
font-size: 14px;
color: #333333;
font-weight: 500;
margin-top: 8px;
padding: 0 24px;
line-height: 40px;
text-transform: uppercase;
"
>
<b>CONFIRMAR CADASTRO</b>
</a>
Loading

0 comments on commit 3b17ecb

Please sign in to comment.