Criando serviço de envio de e-mail com ELIXIR!🔮
Elixir é uma linguagem de programação incrível e nesse post eu resolvi criar um pequeno serviço de e-mail para falar um pouco dela.
Que tal criar um mini servidor HTTP para envio de e-mail SMTP com o Elixir?
Nesse post vou demonstrar como criar um super simples, pequeno e muito leve. Também vamos ver como fazer envio de e-mail quando o usuário acessar uma determinada rota do servidor.
Iniciando
Primeiro precisamos preparar nosso ambiente, caso você ainda não tenha o Elixir no seu ambiente, basta seguir esse guia oficial que é simples e bem detalhado.
Com o Elixir instalado, vamos criar um novo projeto executando o seguinte comando no terminal:
mix new email --sup
Desta forma vamos criar um novo projeto utilizando o Mix, que é uma ferramenta que vem junto com o Elixir para criar, testar e compilar códigos em Elixir, além de gerenciar dependências.
O parâmetro --sup
é para que possamos gerar uma aplicação com o esqueleto no padrão OTP.
Instalando dependências
Podemos navegar até o nosso projeto e abri-lo no editor de código para agora instalar as dependências que vamos usar, são elas:
- plug_cowboy: Uma implementação do Cowboy para o Elixir.
- poison: Biblioteca JSON para o Elixir.
- plug: Uma especificação para componentes e adaptadores web (uma forma de padronizar o objeto de conexão).
- bamboo: Envio de e-mail com Elixir.
- bamboo_smtp: Adaptador para usarmos SMTP no bamboo.
Para isso, vamos abrir o arquivo mix.exs
que fica na raiz do projeto e adicionar as seguintes linhas dentro do bloco deps
:
{:plug, "~> 1.5"},
{:plug_cowboy, "~> 1.0"},
{:poison, "~> 3.1"},
{:bamboo, "~> 2.1.0"},
{:bamboo_smtp, "~> 4.0.1"}
Agora no terminal vamos instalar de fato as dependências(baixa-las), para isso execute o comando:
mix deps.get
Criando servidor HTTP
Com as dependências instaladas vamos começar configurar nosso servidor HTTP, para isso vamos configurar a inicialização dele, abra o arquivo lib/email/application.ex
e adicione a seguinte linha dentro da lista children
:
Plug.Adapters.Cowboy.child_spec(scheme: :http, plug: Email.Router, options: [port: 8085])
Pela ordem de parâmetros:
- Schema é o protocolo que vamos utilizar: HTTP(tcp) ou HTTPS(ssl).
- plug é para que possamos informar um Plug personalizado, nesse caso será o nosso router (eu recomendo essa leitura aqui para ficar mais claro).
- Options são opções que podemos passar para o servidor, neste caso usamos apenas a porta, você pode ver outras aqui.
Como especificamos nosso modulo Email.Router
, precisamos cria-lo agora, para isso, dentro da pasta lib/email
crie um arquivo com o nome email_router.ex
e dentro dele vamos declarar o nosso modulo e rotas, dessa forma:
defmodule Email.Router do
use Plug.Router
use Plug.Debugger
require Logger
plug(Plug.Logger, log: :debug)
plug(:match)
plug(:dispatch)
get "/" do
send_resp(conn, 200, "Server rodando...")
end
match _ do
send_resp(conn, 404, "Pagina não encontrada")
end
end
Após definir nosso modulo, utilizamos o use
para injetar dois módulos no contexto do nosso router.
Com require Logger
vamos importar alguns recursos do logger (exceto funções). Temos algumas chamadas plug
, que basicamente vão configurar os módulos de log
, match
(para fazer o match das rotas de acordo com a requisição) e dispatch
(processar a requisição após o match).
Na última parte do arquivo, temos as nossas rotas: uma GET na raiz que responde com status code 200
e uma mensagem, e a segunda que serve como um fallback, para caso a rota acessada não exista previamente na aplicação, renderizando um texto de "Pagina não encontrada".
Rodando servidor HTTP
Agora vamos compilar e rodar nosso servidor, para isso rode no seu terminal o seguinte comando:
iex -S mix
Agora basta acessar o endereço: http://localhost:8085/ e vamos ver nosso servidor rodando:
Enviando e-mail
Para fazermos o envio do e-mail, vamos começar configurando nosso servidor SMTP, para esse tutorial, vou utilizar o Mailtrap. Os Emails enviados pelo Mailtrap no plano gratuito não vão chegar na caixa de entrada do email de destino informado (gmail, hotmail, etc), eles sempre irão para a caixa de entrada do Mailtrap.
Na raiz do nosso projeto vamos criar uma pasta config
e um arquivo config.exs
dentro dela, o module Config é utilizado para definirmos várias configurações do nosso aplicativo, além de configurações do iex
também.
Nele vamos colocar nossa configuração de SMTP, o conteúdo ficará dessa forma:
use Mix.Config
config :email, Email.Mailer,
adapter: Bamboo.SMTPAdapter,
server: "SERVER",
hostname: "SERVER",
port: 2525,
username: "USER", # or {:system, "SMTP_USERNAME"}
password: "PASS", # or {:system, "SMTP_PASSWORD"}
tls: :always, # can be `:always` or `:never`
allowed_tls_versions: [:"tlsv1", :"tlsv1.1", :"tlsv1.2"], # or {:system, "ALLOWED_TLS_VERSIONS"} w/ comma seprated values (e.g. "tlsv1.1,tlsv1.2")
ssl: false, # can be `true`
retries: 1,
no_mx_lookups: false, # can be `true`
auth: :if_available # can be `:always`. If your smtp relay requires authentication set it to `:always`.
Basta preencher com suas informações e pronto (você pode ver um exemplo preenchido aqui).
Vamos precisar criar um modulo mailer
passando o nome da nossa aplicação, para isso, crie um arquivo chamado mailer.exs
dentro de lib/email
e dentro dele vamos por:
defmodule Email.Mailer do
use Bamboo.Mailer, otp_app: :email
end
Agora abra o arquivo email_router.ex
e na rota de GET
vamos adicionar o seguinte:
import Bamboo.Email #no início do arquivo
...
new_email()
|> to("[email protected]")
|> from("[email protected]")
|> subject("Teste")
|> text_body("Testando envio de email")
|> Email.Mailer.deliver_now
Aqui o código começa a ficar um pouco "estranho" pra quem não tem contato com Elixir, mas vou explicar: Primeiro fazemos o import
do modulo "Email" dentro de "Bamboo", dessa forma temos acesso as funções contidas no modulo.
Em seguida fazemos uma chamada a função new_email()
que vem do modulo que importamos e começamos uma sequência de pipe. Utilizamos o pipe para pegar o resultado de uma expressão e lançar como primeiro argumento de uma outra. Esteticamente lembra o fluent pattern.
Agora, basta rodar nosso servidor novamente e acessarmos nossa rota GET
e verificar o e-mail do Mail trap:
iex -S mix
Nossa caixa de entrada no Mailtrap:
Conclusão
Podemos melhorar ainda mais esse código, podemos por exemplo pegar os parâmetros de envio do e-mail (destinatário, mensagem e assunto) via GET
ou POST
, podemos também carregar as informações do SMTP através de variaveis de ambiente, deixando a aplicação mais simples de modificar (caso eu tenha mais de um abiente) e mais segura.
Espero que tenha gostado, já faz algum tempo que queria escrever sobre Elixir e foi super legal.
Aqui está o projeto finalizado.
Veja esse episódio super legal do Coffee Zone onde falamos de Elixir.