Search code examples
node.jssmtpnodemailerdotenv

Nodemailer SMTP not working on production server


I am having issues sending email via nodemailer - SMTP(from another host) on production

i uploaded my API on a server(Scaleway Dev), i'm using Ubuntu Bionic and while testing noticed it is not sending emails(which i need for verification of a user).

at first i thought the request isn't getting to the server, but when i tried logging in i got a "confirm your password" response, i check the mongoDB database and the user is there, but still no confirmation email.

I tried checking it on localhost, thinking it might be the dotenv dependency, but it works there, what gives?

node version on my server is 8.10.0 and on my personal computer 11.12.0

these are my dependencies

    enter code here
    "dependencies": {

    "bcrypt": "^3.0.6",
    "body-parse": "^0.1.0",
    "client-sessions": "^0.8.0",
    "connect": "^3.6.6",
    "cookie-parser": "~1.4.4",
    "cors": "^2.8.5",
    "debug": "~2.6.9",
    "dotenv": "^8.0.0",
    "express": "~4.16.1",
    "express-session": "^1.16.1",
    "express-validator": "^5.3.1",
    "http-errors": "~1.6.3",
    "moment": "^2.24.0",
    "mongoose": "^5.5.8",
    "morgan": "~1.9.1",
    "nodemailer": "^6.1.1",
    "nodemon": "^1.19.0",
    "passport": "^0.4.0",
    "pug": "2.0.0-beta11",
    "randomstring": "^1.1.5",
    "session": "^0.1.0",
    "session-mongoose": "^0.5.2"
}

these options used are specified by the host that i'm using

//this is my transporter constant

    const transporter   = nodemailer.createTransport({
    host: '*different host from the server*',
    port: 465,
    secure: true,
    auth: {
        user: my used email(hardcoded),
        pass: process.env.EMAILPASS
    },
    tls: {
        rejectUnauthorized: false
    }
});

//my email options

    let mailOptions ={
                from: '"Company Name <noreply@*different host DNS*>',
                to: req.body.email,
                subject: *subject*
                html: `Email Content with confirmation token`
            }

//emailing the message itself

    transporter.sendMail(mailOptions, (err, info) => {
                if(err){
                    return console.log(err);
                }
                console.log("message sent");
            });

i'm using this email generator(https://generator.email/) for fast throwaway emails. the mailing starts after i save the user.

I'm perplexed as to what should i do... any and all help is appreciated


Solution

  • I have had issues with nodemailer in the past. I'm using mailgun (https://www.mailgun.com/) to send my emails. They offer 10,000 emails a month for free. Here is a code that works with mailgun:

    dependencies:

    "express": "4.16.4",
    "config": "3.0.1",
    "nodemailer": "5.1.1",
    "nodemailer-mailgun-transport": "1.4.0"
    

    code (it is wrapped inside an express router) :

    const config = require('config');
    const nodemailer = require('nodemailer');
    const mg = require('nodemailer-mailgun-transport');
    const express = require('express');
    const router = express.Router();
    
    router.post('/', async (req, res) => {
    
        //the data has to be an array. It will send as many emails as the number of items in the array
        var emailsList = ["[email protected]"];
        emailsList[0].name = "Test Name";
    
        var auth = {
            auth: {
                api_key: config.get('mailgunApiKey'),
                domain: config.get('mailgunDomain')
            }
        };
    
        transporter = nodemailer.createTransport(mg(auth)),
        EmailTemplate = require('email-templates').EmailTemplate,
        path = require('path'),
        Promise = require('bluebird');
    
        function sendEmail (obj) {
            return transporter.sendMail(obj);
        }
    
        function loadTemplate (templateName, contexts) {
            let template = new EmailTemplate(path.join(__dirname, '../templates', templateName));
            return Promise.all(contexts.map((context) => {
                return new Promise((resolve, reject) => {
                    template.render(context, (err, result) => {
                        if (err) reject(err);
                        else resolve({
                            email: result,
                            context,
                        });
                    });
                });
            }));
        }
    
        loadTemplate('dailyReferralEmail', emailsList).then((results) => {
            return Promise.all(results.map((result) => {
                sendEmail({
                    to: result.context.email,
                    from: 'Your Name <[email protected]>',
                    'h:Reply-To': '[email protected]',
                    subject: result.email.subject,
                    html: result.email.html,
                    text: result.email.text,
                });
            }));
        }).then(() => {
    
            var response = {
                text: "Email sent"
            }
            JSON.stringify(response);
            res.status(200).send(response);
        });
    });
    
    module.exports = router; 
    

    As a template generator, I'm using HBS. So you must have a templates folder in the root folder of your project, with this tree:

    enter image description here

    You can use your variables inside your email with {{ }}.

    Inside html.hbs:

    <p>Hello {{name}}</p>
    

    Inside subject.hbs

    Subject of your email
    

    Inside text.hbs

    Preview text of your email
    

    Hope this helps!