Hoje quero compartilhar com você como enviar SMS em NodeJS usando o serviço SNS da AWS. Esta aplicação é um micro-serviço e você pode utilizar como um componente do seu software atual. Você só precisa subir a app em algum ambiente node e adicionar itens na fila de notificações.
No exemplo estou usando uma base MongoDB, mas você pode adaptar o serviço para uma base MySQL ou uma fila em um RabbitMQ ou SQS.
Atualmente é comum utilizarmos e-mail ou sms para confirmar um cadastro, alterar senha, validar um celular ou até ajudar na validação de acesso.
O Google, Uber, Facebook e tantas outras empresas usam este tipo de funcionalidade em seus apps, é uma maneira eficiente e rápida de confirmar a autenticidade de um usuário. Neste tutorial vou te ajudar aplicar o mesmo recurso em seu software.
O que você precisa saber
O Amazon Simple Notification Service (SNS) é uma solução para envio de sms e notificações push, principalmente para envio de mensagens curtas, promocionais, notícias e avisos de atualizações.
Você pode enviar para mais de 200 países e conta com a escalabilidade e flexibilidade que praticamente todo serviço AWS oferece. Porém, este serviço tem custos, em geral você vai pagar pelo envio da notificação e o tráfego de saída.
No caso do SMS, os preços podem variar também por região e operadora de destino, consulte a página de pricing para não ter surpresas no fim do mês. 😉
Outro ponto importante é os tipos de conteúdo das mensagens, Transacionaos e Promocionais. Para cada também há um pricing diferente e regras de envio que você precisa considerar na integração. Neste exemplo, vamos enviar mensagens transacionais, porque é um shortcode para validar um cadastro.
Quer saber mais sobre os serviços da AWS, como usar em seu projeto e por onde começar? Cadastre-se na minha lista de e-mails e receba dicas práticas semanalmente.
Criando a aplicação
Vou ser direto neste tutorial, em breve este conteúdo vai estar gravado e disponível no meu canal no Youtube e lá vou explicar com mais detalhes cada etapa.
Dependências e Setup
Vamos criar um diretório para nosso app e adicionar as dependências.
mkdir bot-sendsms && cd bot-sendsms && npm init -f npm i --save aws-sdk dotenv mongoose interval-promise babel babel-cli npm i --save-dev babel-preset-env
Agora vamos criar o arquivo babel.rc e adicionar o preset env:
{ "presets": ["env"] }
Adicione o arquivo .env para as variáveis de conexão ao MongoDB e as chaves de acesso ao seu perfil na AWS.
DB_MONGO_HOSTNAME = 'your_host_mongodb' DB_MONGO_USERNAME = 'your_user' DB_MONGO_PASSWORD = 'your_pass' DB_MONGO_DATABASE = 'your_db_name' DB_MONGO_PORT = 00000 AWS_ACCESS_KEY_ID = 'your_key' AWS_SECRET_ACCESS_KEY = 'your_secret_key'
Acessando o MongoDB
Vamos criar a estrutura do model para manipular nossos dados, no seu MongoDb crie uma collection chamada notifications, após crie o diretório src e adicione o arquivo model.js com o seguinte script:
export default (conn, mongoose) => { return conn.model("notifications", new mongoose.Schema({ to: { type: String, required: true, }, body: { type: String, required: true, }, sended: { type: Boolean, default: false, required: true, }, createdAt: { type: Date, default: Date.now, }, sendedAt: Date, })); };
Agora crie o diretório util na raiz de sua app e adicione o arquivo datasource.js com o seguinte script de conexão.
import dotenv from 'dotenv' import mongoose from 'mongoose' import model from '../src/model' dotenv.config() const database = process.env.DB_MONGO_DATABASE const username = process.env.DB_MONGO_USERNAME const password = process.env.DB_MONGO_PASSWORD const hostname = process.env.DB_MONGO_HOSTNAME const port = process.env.DB_MONGO_PORT let datasource = null; export default () => { if (!datasource) { const uri = `mongodb://${hostname}:${port}/${database}`; const options = { user: username, pass: password, useNewUrlParser: true, }; const connection = mongoose.createConnection(uri, options); connection.Promise = global.Promise; const models = []; const modelNotifications = model(connection, mongoose); models[modelNotifications.modelName] = modelNotifications; datasource = { connection, mongoose, models, }; } return datasource; };
Consultando e atualizando o MongoDB
Crie o arquivo service.js em src e adicione o script a seguir.
O que fizemos foi criar dois métodos. O getAllToSend retornando a lista de notificações pendentes, limitando a quantidade de itens e ordenando pela data de criação. O updateToSended só atualiza a notificação.
export default (model) => { const service = { getAllToSend(amount) { return new Promise((resolve, reject) => { model.find({ sended: false }).sort({ createdAt: 'asc' }).limit(amount) .then(items => { if (items) { resolve(items) } resolve(); }) .catch(err => { reject(err) }) }) }, updateToSended(id) { return new Promise((resolve, reject) => { model.findById(id) .then(notification => { const update = notification; update.sended = true; update.sendedAt = Date.now() update.save() resolve() }) .catch(err => { reject(err) }) }) } } return service; }
Enviando o SMS com a API SNS
Adicione o arquivo sms.js em /src com o script a seguir.
O que estamos fazendo é publicar nosso SMS no Simple Notification Service (SNS). Você precisa definir a região que vai utilizar, instanciar o serviço passando a versão da API e adicionar o atributo DefaultSMSType com o valor “Transactional”.
O conteúdo do SMS é um objeto com os parâmetros PhoneNumber, Message e MessageStructure. Com isto pronto, você chama o método publish.
import AWS from 'aws-sdk' AWS.config.update({ region: 'us-west-2' }) export default () => { const sms = { send(notification) { return new Promise(async(resolve, reject) => { const sns = new AWS.SNS({ apiVersion: '2010-03-31' }) sns.setSMSAttributes({ attributes: { DefaultSMSType: 'Transactional' }, function(error) { if (error) reject(error) } }) const params = { PhoneNumber: notification.to, Message: notification.body, MessageStructure: 'string' } sns.publish(params, (err, data) => { if (err) { reject(err) } resolve() }) }) } } return sms; }
Unindo todos os eventos
Agora vamos criar o index.js na raiz da app.
Neste arquivo vamos criar um método assíncrono para chamar a função getAllToSend a cada 5 segundos e publicar o SMS na fila do SNS.
import datasource from './util/datasource' import sms from './src/sms' import service from './src/service' import interval from 'interval-promise' const db = datasource() const model = db.models.notifications const controller = service(model) async function main() { try { const notifications = await controller.getAllToSend(5); if (notifications !== undefined && notifications.length > 0) { console.log(`Sending ${notifications.length} SMS`) for (let index = 0; index < notifications.length; index++) { const notification = notifications[index]; await sms().send(notification) .then(() => { controller.updateToSended(notification.id) }) .catch(err => { console.log('Could not send.') console.error(err) }) } } else { console.log('No SMS to send.') } } catch (error) { console.error(error) } } interval(async () => { await main() }, 5000)
Você pode alterar o valor passado no método getAllToSend para a quantidade que preferir e também o intervalo de 5 segundos.
No exemplo eu peguei as últimas 5 notificações, percorro o array caso tenha algum item e chamo o evento send(), função criada no src/sms. Caso o envio aconteça com sucesso, atualizo a notificação, caso contrário apenas exibo no meu terminal. Nesta exception você pode registrar um log ou adaptar ao que fizer mais sentido para seu contexto.
Agora vamos finalizar, adicione o script para start da sua app no package.json.
"scripts": { "start": "babel-node index.js" },
Pronto!
Agora é só digitar npm start no seu terminal e ver sua app rodar.


Este tutorial é um micro-serviço para rodar em qualquer ambiente nodejs. Você precisa apenas adicionar itens na fila de envio e deixar em execução. Embora este script apenas envie uma mensagem transacional, você pode customizar. Confira a documentação na AWS e adapte a sua necessidade.
O script não tem regras de negócio, é apenas um sender, a checagem do código ou a criação da mensagem é responsabilidade da sua aplicação. Você apenas vai se conectar no mongo e adicionar o item na fila.
Este micro-serviço pode evoluir para uma function serverless, na AWS você tem Lambda Functions, além disso pode integrar com o SQS e Cloud Watch. Seria necessário fazer algumas adaptações, mas o resultado seria ainda mais eficiente.
Espero ter ajudado, o código fonte deste script está neste repositório, qualquer dúvida ou sugestão deixa nos comentários. 🙂