Envio de e-mail com aws ses
Nesta publicação vamos implementar uma integração com serviço AWS SES e vamos criar uma aplicação completa em que é possível enviar um e-mail.
Para esta implementação vamos utilizar as seguintes tecnologias, que utiliza o backend para renderizar o frontend e integrar o serviço da aws. É uma aplicação tradicional html renderizada no servidor (server side rendering). No modelo single page application
.
- nodejs para backend e frontend (utilizando html puro)
- aws ses
O aws ses (é um serviço pago), essa implementação é uma prova de conceito de implementação de uma página de contato em que é enviado um e-mail para mim mesmo. Via o serviço da aws ses.
Você pode ver um exemplo do funcionamento da página aqui. Esta página não possui integração com o backend, está disponível apenas para ser ter uma ídeia do funcionamento e como ficará o projeto depois de pronto (do ponto de vista de apresentação).
Implementando o frontend
A implementação do frontend possui apenas duas rotas uma para a GET vai renderizar o formulário de contato.
export default function layout({ contato }) {
const { email, message, title, errors } = contato;
return `
<html lang="pt-br">
<head>
<title>Sendmail app</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body class="">
<nav class="container-fluid navbar navbar-expand navbar-light bg-light">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
</ul>
</nav>
<main class="mt-4 container py-4 position-relative">
<h2>Contato</h2>
<form method="post" class="has-validation mt-3" action="/">
<div class="mb-3">
<label for="servicestatus" class="form-label"></label>
<input type="hidden" class="form-control ${errors.service.length ? 'is-invalid': ''}" id="servicestatus" name="servicestatus" value="">
<div class="invalid-feedback">
${errors.service.length > 0 ? errors.service[0]: ''}
</div>
</div>
<div class="mb-3">
<label for="email" class="form-label">E-mail</label>
<input type="text" class="form-control ${errors.email.length ? 'is-invalid': ''}" id="email" name="email" value="${email}">
<div class="invalid-feedback">
${errors.email.length > 0 ? errors.email[0]: ''}
</div>
</div>
<div class="mb-3">
<label for="title" class="form-label">Título</label>
<input type="text" class="form-control ${errors.title.length ? 'is-invalid': ''}" id="title" name="title" value="${title}">
<div class="invalid-feedback">
${errors.title.length > 0 ? errors.title[0]: ''}
</div>
</div>
<div class="mb-3">
<label for="message" class="form-label">Mensagem</label>
<textarea class="form-control ${errors.message.length ? 'is-invalid': ''}" id="message" name="message">${message}</textarea>
<div class="invalid-feedback">
${errors.message.length > 0 ? errors.message[0]: ''}
</div>
</div>
<button id="btnenviar" type="submit" class="btn btn-primary">
Enviar </button>
</form>
</main>
</body>
</html>
`;
}
Outra a mesma rota para o POST que vai fazer a validação dos dados do formulário e caso esteja tudo certo fará o envio do e-mail. Caso seja feito o envio com sucesso, então sera exibida uma tela de sucesso ao enviar.
export default function sucesso() {
return `
<html lang="pt-br">
<head>
<title>Sendmail app</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body class="">
<nav class="container-fluid navbar navbar-expand navbar-light bg-light">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
</ul>
</nav>
<main class="mt-4 container py-4 position-relative">
<div class="row justify-content-md-center">
<div class="col col-md-auto text-center">
<div id="sucesso" class="d-flex justify-content-center h1"> Mensagem enviada com sucesso
</div>
<br>
<a href="/" class="btn btn-primary justify-content-center" role="button">Voltar</a>
</div>
</div>
</main>
</body>
</html>
`;
}
Agora para integrar os serviços vamos implementar a funcionalidade de envio de e-mai, como dito, o envio será feito via o serviço AWS simple email service
Para isso vamos apenas adicionar a biblioteca do aws sdk, e criar uma instância do servico SES, ele vai ficar responsável pelo envio do e-mail.
Vamos instalar o sdk da aws, para isso utilize o npm install
npm install @aws-sdk/client-sesv2
Após fazer essa instalação, edite o arquivo server/index.js
, adicionar o import e fazer as configurações básicas para o envio de um e-mail, nesta tarefa fomos guiados pela documentação da AWS do serviço sesv2.
O resultado final fica assim, aqui vou mostrar apenas a implementação do método sendMail
:
async sendMail(req, res) {
const contato = new Contato(req.body)
if (contato.email.trim() === '') {
contato.errors.email.push('E-mail não pode ser vazio')
}
if (contato.title.trim() === '') {
contato.errors.title.push('Título não pode ser vazio')
}
if (contato.message.trim() === '') {
contato.errors.message.push('Mensagem não pode ser vazio')
}
if (contato.errors && (contato.errors.email.length > 0 || contato.errors.message.length > 0 || contato.errors.title.length > 0)) {
return res.send(layout({ contato: contato }))
} //até aqui faz validação dos campos obrigatórios, renderiza o form com as mensagens de erro e os dados do formulário
const input = { // SendEmailRequest
FromEmailAddress: "contato@danizavtz.com.br",
ReplyToAddresses: [
"daniellucena@yahoo.com.br",
],
Destination: { // Destination
ToAddresses: [ // EmailAddressList
"daniellucena@yahoo.com.br",
]
},
Content: { // EmailContent
Simple: { // Message
Subject: { // Content
Data: req.body.title, // required
Charset: "UTF-8",
},
Body: { // Body
Text: {
Data: `Mensagem de: ${req.body.email}, \nMensagem: ${req.body.message}`, // required
Charset: "UTF-8",
}
}
}
}
};
const command = new SendEmailCommand(input);
try {
await client.send(command);
res.send(sucesso())
} catch (err) {
console.log(err); //esta linha não é necessária, é utilizada apenas para debug
contato.errors.service.push('Houve um erro durante o envio')
return res.send(layout({ contato: contato }))
}
}
Repare que temos um input do tipo "hidden", ele serve para incluir a mensagem de erro no caso de haver um erro no envio, (quando esse erro vem do serviço aws-ses).
Veja a versão completa deste projeto.