Search code examples
javascriptnode.jstwiliosendgridnodemailer

Trying to send email with Nodemailer and Twilio Sendgrid with normal auth (not Oauth2). SendMessage() fails with Error: Missing credentials for PLAIN


I am attempting to send an email using Nodemailer and Twilio Sendgrid, following the tutorial here. As far as I can tell I am following the instructions in the tutorial, as well as theNodemailer and Sendgrid documentation. Every time this method is called, the code in the catch block executes, and I get the error Error: Missing credentials for "PLAIN".

My question was closed due to association with the question here, however my problem is different and none of the solutions on the thread apply. I am using my own domain to send, not gmail.com. I want to solve the problem without using Oauth2, which from what I understand I should not need, given that I am using an email domain I control. Also I am already using pass' rather than 'password for my authorization data (the top solution on the associated answer).

I've been stuck on this for a few days now , and I'd appreciate any insight anyone can offer!

Here is my code:

async function sendEmail(email, code) {
    try{
        const smtpEndpoint = "smtp.sendgrid.net";
        const port = 465;
        const senderAddress = 'Name "contact@mydomain.com"';
        const toAddress = email;
        const smtpUsername = "apikey";
        const smtpPassword = process.env.SG_APIKEY;
        const subject = "Verify your email";

        var body_html = `<!DOCTYPE> 
        <html>
          <body>
            <p>Your authentication code is : </p> <b>${code}</b>
          </body>
        </html>`;

        let transporter = nodemailer.createTransport({
          host: smtpEndpoint,
          port: port,
          secure: true, 
          auth: {
            user: smtpUsername,
            pass: smtpPassword,
          },
          logger: true,
          debug: true,
        });
        
        let mailOptions = {
          from: senderAddress,
          to: toAddress,
          subject: subject,
          html: body_html,
        };

        let info = await transporter.sendMail(mailOptions);
        return { error: false };
    } catch (error) {
    console.error("send-email-error", error);

    return {
      error: true,
      message: "Cannot send email",
    };
  }
}

And here is the log: error log in bash terminal

Thanks!


Solution

  • You have already identified the issue of API key not being passed into the Nodemailer transport. While hardcoding the key is a possible solution, it's not a good practice. Usually secrets and keys are managed via environment variables so they are, for example, not accidentally committed to a repository and can be configured externally without changing the code.

    In the tutorial you linked, working with the environment variable is addressed, but I see there is a mistake with .env file. So let me try to recap how to properly get SG_APIKEY from environment variable and .env file.

    • In your project directory create the .env file with the following contents:
      SG_APIKEY=<your_sendgrid_api_key>
      
      (obviously replace <your_sendgrid_api_key> with your actual API key)
    • Make sure dotenv package is installed: npm i dotenv
    • At the beginning of the file where you use Nodemailer, add the following line:
      require("dotenv").config();
      
      This will ensure the SG_APIKEY is loaded from .env file.
    • You can check if the env variable is set correctly with console.log(process.env.SG_APIKEY)