Missing credentials for "PLAIN" nodemailer
Asked Answered
C

16

61

I'm trying to use nodemailer in my contact form to receive feedback and send them directly to an email. This is the form below.

<form method="post" action="/contact">
      <label for="name">Name:</label>
      <input type="text" name="name" placeholder="Enter Your Name" required><br>
      <label for="email">Email:</label>
      <input type="email" name="email" placeholder="Enter Your Email" required><br>
      <label for="feedback">Feedback:</label>
      <textarea name="feedback" placeholder="Enter Feedback Here"></textarea><br>
      <input type="submit" name="sumbit" value="Submit">
</form>

This is what the request in the server side looks like

app.post('/contact',(req,res)=>{
let transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
        user: '[email protected]',
        password: 'password'
    }
});
var mailOptions = {
    from: req.body.name + '&lt;' + req.body.email + '&gt;',
    to: '[email protected]',
    subject: 'Plbants Feedback',
    text: req.body.feedback 
};
transporter.sendMail(mailOptions,(err,res)=>{
    if(err){
        console.log(err);
    }
    else {

    }
});

I'm getting the error Missing credentials for "PLAIN". Any help is appreciated, thank you very much.

Charnel answered 18/2, 2018 at 16:42 Comment(0)
E
67

You have

auth: {
    user: '[email protected]',
    password: 'password'
}

But you should write this

auth: {
    user: '[email protected]',
    pass: 'password'
}

Just rename password to pass.

Edelman answered 16/10, 2019 at 17:50 Comment(2)
you deserve an aaward! this saved me thank youCuenca
Simple and direct, live saver. Just renaming the password to pass. solves this. You might have mistakenly written password instead of just passMalignancy
H
29

I was able to solve this problem by using number 3, Set up 3LO authentication, example from the nodemailer documentation (link: https://nodemailer.com/smtp/oauth2/). My code looks like this:

let transporter = nodemailer.createTransport({
    host: 'smtp.gmail.com',
    port: 465,
    secure: true,
    auth: {
        type: 'OAuth2',
        user: '[email protected]',
        clientId: '000000000000-xxx0.apps.googleusercontent.com',
        clientSecret: 'XxxxxXXxX0xxxxxxxx0XXxX0',
        refreshToken: '1/XXxXxsss-xxxXXXXXxXxx0XXXxxXXx0x00xxx',
        accessToken: 'ya29.Xx_XX0xxxxx-xX0X0XxXXxXxXXXxX0x'
    }
});

If you looked at the example in the link that I stated above, you can see there that there is a 'expires' property but in my code i didn't include it and it still works fine.

To get the clientId, clientSecret, refreshToken, and accessToken, I just watched this video https://www.youtube.com/watch?v=JJ44WA_eV8E .

I don't know if this is still helpful to you tho.

High answered 10/7, 2018 at 0:54 Comment(1)
Here you will find a good and more recent video: youtube.com/watch?v=-rcRf7yswfMNonpayment
S
10

Gmail / Google app email service requires OAuth2 for authentication. PLAIN text password will require disabling security features manually on the google account.

To use OAuth2 in Nodemailer, refer: https://nodemailer.com/smtp/oauth2/

Sample code:

var email_smtp = nodemailer.createTransport({      
  host: "smtp.gmail.com",
  auth: {
    type: "OAuth2",
    user: "[email protected]",
    clientId: "CLIENT_ID_HERE",
    clientSecret: "CLIENT_SECRET_HERE",
    refreshToken: "REFRESH_TOKEN_HERE"                              
  }
});

And if you still want to use just plain text password, disable secure login on your google account and use as follows:

var email_smtp = nodemailer.createTransport({      
  host: "smtp.gmail.com",
  auth: {
    type: "login", // default
    user: "[email protected]",
    pass: "PASSWORD_HERE"
  }
});
Steatite answered 22/2, 2018 at 10:21 Comment(1)
Previous version of Nodemailer (not sure which version) required usage of xoauth2.createXOAuth2Generator to handle OAuth2. It is no longer required.Steatite
S
8

For me the issue was that I wasn't accessing the .env file variables properly (I assume you're storing your email and password in a .env file too). I had to add this to the top of the file:

const dotenv = require('dotenv');
dotenv.config();

Once I did that I could fill out the "auth" portion of the credentials like this:

auth: {
  user: process.env.EMAIL_USERNAME,
  pass: process.env.EMAIL_PASSWORD
}

Of course you need to replace EMAIL_USERNAME and EMAIL_PASSWORD with whatever you called those variables in your .env file.

Sherard answered 23/3, 2021 at 22:54 Comment(0)
J
7

We don't need to lower our Google Account Security for this. This works for me on localhost and live server. Versions: node 12.18.4, nodemailer ^6.4.11.

STEP 1: Follow setting up your Google Api Access in this video AND IGNORE his code (it didn't work for me): https://www.youtube.com/watch?v=JJ44WA_eV8E

STEP 2: Try this code in your main app file after you install nodemailer and dotenv via npm i nodemailer dotenv:

    require('dotenv').config();  //import and config dotenv to use .env file for secrets
    const nodemailer = require('nodemailer');

    function sendMessage() {
      try {
        // mail options
        const mailOptions = {
          from: "[email protected]",
          to: "[email protected]",
          subject: "Hey there!",
          text: "Whoa! It freakin works now."
        };
        // here we actually send it
        transporter.sendMail(mailOptions, function(err, info) {
          if (err) {
            console.log("Error sending message: " + err);
          } else {
            // no errors, it worked
            console.log("Message sent succesfully.");
          }
        });
      } catch (error) {
        console.log("Other error sending message: " + error);
      }
    }

    // thats the key part, without all these it didn't work for me
    let transporter = nodemailer.createTransport({
      host: 'smtp.gmail.com',
      port: 465,
      secure: true,
      service: 'gmail',
      auth: {
            type: "OAUTH2",
            user: process.env.GMAIL_USERNAME,  //set these in your .env file
            clientId: process.env.OAUTH_CLIENT_ID,
            clientSecret: process.env.OAUTH_CLIENT_SECRET,
            refreshToken: process.env.OAUTH_REFRESH_TOKEN,
            accessToken: process.env.OAUTH_ACCESS_TOKEN,
            expires: 3599
      }
    });

    // invoke sending function
    sendMessage();

Your .env file for the above code should look similar to this:

[email protected]
GMAIL_PASSWORD=lakjrfnk;wrh2poir2039r
OAUTH_CLIENT_ID=vfo9u2o435uk2jjfvlfdkpg284u3.apps.googleusercontent.com
OAUTH_CLIENT_SECRET=og029503irgier0oifwori
OAUTH_REFRESH_TOKEN=2093402i3jflj;geijgp039485puihsg[-9a[3;wjenjk,ucv[3485p0o485uyr;ifasjsdo283wefwf345w]fw2984329oshfsh
OAUTH_ACCESS_TOKEN=owiejfw84u92873598yiuhvsldiis9er0235983isudhfdosudv3k798qlk3j4094too283982fs
Juarez answered 28/9, 2020 at 10:22 Comment(1)
You know the feeling when you search for this simple solution for 2 days and you don't find anything. And when you do you post it here and see that 3 people above you already posted it and you just didn't see it before! :-PJuarez
I
6

This happened to me when I tried to send mail to MailHog, a development local mailserver which runs on port 1025, and uses no username/password by default.

My code was providing empty username/password, but in fact you should provide no credentials at all.

This does not work (results in 'Missing credentials for "PLAIN"'):

const transport = require('nodemailer').createTransport({
  host: mailhog,
  port: 1025,
  secure: false,
  auth: {
    user: '',
    pass: '',
  },
});

But this works:

const transport = require('nodemailer').createTransport({
  host: mailhog,
  port: 1025,
  secure: false,
});
Intellectualize answered 26/7, 2022 at 3:24 Comment(1)
With Strapi v4 I prefer to use auth: false in ./config/env/{env}/plugins.ts, while auth: {user: 'user', pass: 'pass',} in ./config/plugins.tsRedskin
S
2

For me it happened because I forgot to npm install dotenv and require('dotenv').config();

Stronghold answered 4/11, 2020 at 20:42 Comment(0)
M
2

I came across this issue when deploying my app to Heroku. I was sending emails fine locally, but when I pushed a new build to Heroku, I got the dreaded Missing credentials for "PLAIN" error. My issue was that I hadn't separately setup the .env variables in Heroku.

If you go to your dashboard in Heroku, you can manually set up the config variables and that solved the problem for me.

Or you can do via Heroku CLI - good tutorial here

Heroku Dashoard

Myrlemyrlene answered 16/6, 2021 at 10:9 Comment(1)
This is my issue! Thanks for saving me from days of confusion.Blare
S
1

For me it was because I forgot to add my Gmail password to my .env file.

Spalla answered 23/6, 2020 at 13:42 Comment(0)
R
1

I was running ts-node in a folder that didn't have the .env file.

So my process.env.GMAIL_EMAIL and process.env.GMAIL_PASS weren't defined.

When I ran it in the directory with the .env, it worked

Rawson answered 14/12, 2020 at 14:28 Comment(0)
C
1

If you are going to use the basic authentication (your current configuration) you will need to activate less secure app access from the following link to your google account which was stated in node mailer site here.

Also for more secure way, I recommend to take a look on the two following links:

Note: if you are going to use the secure way from the first link steps you should modify the auth attributes to add the type option like the following:

auth: {
type: 'OAuth2',
user: process.env.EMAIL,
accessToken,
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
refresh_token: process.env.REFRESH_TOKEN
}

because without stating explicitly that you are using OAuth2 method it will print the same error to you (based on my recent trials using the written code in that link)

Calorifacient answered 11/3, 2021 at 2:6 Comment(0)
D
1

I had the same issue on render server and my own case can occur on any server.

I was able to fix this issue by doing the following

  • log the transporter object
  • check all the properties and values if its there or correct
  • then I discovered pass field value was showing undefined.
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,

}

  • I later discovered I didn't add Email_Pass in my local env variable to my environment variable on the render server. And after adding it my problem was solved.

I hope this is helpful to someone

Daric answered 3/5, 2023 at 12:21 Comment(0)
A
0

Google disabled less secure apps, to resolve the issue one need to setup "Login with app password" and to allow the app password "setup two factor authentication"

when 2-Step-Verification is on and one get a "password incorrect" error, sign in to your account and go to security, try to use an App Password.

transport: {
  host: 'smtp.gmail.com',
  port: 465,
  secure: true,
  auth: {
    user: '[email protected]',
    pass: 'app password',
  },
},
Androgen answered 18/7, 2022 at 13:32 Comment(0)
M
0

If you are expecting this (ERROR Send Error: Missing credentials for "PLAIN") error, it's probably because you are testing on localhost.

For example, if you are using Heroku, simply try to deploy your project and test it in production.

Regards.

Malignant answered 2/11, 2022 at 7:1 Comment(0)
L
0
const sentEmail = async options =>{
    // 1) Create Transporter
    const transporter = nodemailer.createTransport({
        host: process.env.EMAIL_HOST,
        port: process.env.EMAIL_PORT,
        auth: {
            user: process.env.EMAIL_USERNAME,
            pass: process.env.EMAIL_PASSWORD
        }
    });

    // 2) Define the email options
    const mailOptions = {
        from: "Muhammad Waris <[email protected]>",
        to: options.email,
        subject: options.subject,
        text: options.message,
    }

    // 3) Send email
    transporter.verify(function(error, success) {
        if (error) {
            console.log('Server is not ready to take our messages', error);
        } else {
            console.log('Server is ready to take our messages');
        }
    });

    // 3) Send email
    await transporter.sendMail(mailOptions);
}


Use this method to send email 

   await sendEmail({
            email: user.email,
            subject: 'Your password reset token (valid for 10 min)',
            message
        }); 

    const message = `Forgot your password? Submit a PATCH request with your new password and passwordConfirm to: ${resetURL}.\nIf you didn't forget your password, please ignore this email!`
Lindsay answered 8/5, 2024 at 15:18 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Delegacy
C
-1

I encountered the same problem, and that was caused by Google automatically blocked your logging-in form untruthful third-party software. Then you can just turn this feature off in your Google account management.

Regards,

Cannabis answered 13/4, 2021 at 7:36 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.