«TypeError: Невозможно прочитать свойство 'response' of undefined" в нодмейлере - PullRequest
0 голосов
/ 22 февраля 2020

Обычно я пытаюсь отправить пользователю URL-адрес для сброса его пароля. Я все правильно импортировал из mailer.js и все работало нормально, пока не получил ответ. Он говорит

it can not read property response of undefined.


маршруты / пользователи. js

router.post("/reset-password/:email", emailController.createResetPasswordToken)

утилит / почтовой программы. js

const nodemailer = require("nodemailer")

let transporter = nodemailer.createTransport({
    service: "gmail",
    auth: {
        user: process.env.EMAIL,
        pass: process.env.PASSWORD
    }
})

getPasswordResetURL = (user, token) => {
    return `http://localhost:3000/reset-password/${user._id}/${token}`
}

const resetPasswordTemplate = (user, url) => {
    const from = process.env.EMAIL
    const to = user.email
    const subject = "Password Reset"
    const html = `
        <p>Hey ${user.name || user.email},</p>
        <p>We heard that you forgot your password. Sorry about that!</p>
        <p>But don’t worry! You can use the following link to reset your password:</p>
        <a href=${url}>${url}</a>
        <p>If you don’t use this link within 1 hour, it will expire.</p>
    `
}

module.exports = { transporter, getPasswordResetURL, resetPasswordTemplate }

emailController. js

const User = require("../models/User")
const bcrypt = require("bcrypt")
const jwt = require("jsonwebtoken")
const validator = require("validator")
const { transporter, getPasswordResetURL, resetPasswordTemplate } = require("../utils/mailer")
module.exports = {

    createResetPasswordTokenAndSendMail: (req, res) => {
        const email = req.params.email
            User.findOne({ email }, (err, user) => {
                if (err) console.log(err)
                // res.json({user})
                const hashedPassword = user.password
                const createdAt = user.createdAt
                const userId = user._id
                // console.log(user.password, user.createdAt, userId )
                const secret = hashedPassword + "-" + createdAt
                const token = jwt.sign({ userId }, secret, {
                    expiresIn: 3600
                })
                // console.log(token)
                // console.log(user)
                const url = getPasswordResetURL(user, token) 
                // console.log(url)
                const emailTemplate = resetPasswordTemplate(user, url)
                // console.log(emailTemplate, "l26")

                const sendEmail = () => {
                    transporter.sendMail(emailTemplate, (err, info) => {
                        if (err) console.log(err)
                        // console.log(info, "L31")
                        console.log("email sent successfully", info.response)
                    })
                }
                sendEmail()
        })
    }

}

Когда я тестировал этот API в Почтальоне, я получил эту ошибку в консоли:

{ Error: Missing credentials for "PLAIN"
    at SMTPConnection._formatError (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:784:19)
    at SMTPConnection.login (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:448:38)
    at connection.connect (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-transport/index.js:271:32)
    at SMTPConnection.once (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:215:17)
    at Object.onceWrapper (events.js:313:30)
    at emitNone (events.js:106:13)
    at SMTPConnection.emit (events.js:208:7)
    at SMTPConnection._actionEHLO (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:1313:14)
    at SMTPConnection._processResponse (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:942:20)
    at SMTPConnection._onData (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:749:14)
    at TLSSocket.SMTPConnection._onSocketData.chunk (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:195:44)
    at emitOne (events.js:116:13)
    at TLSSocket.emit (events.js:211:7)
    at addChunk (_stream_readable.js:263:12)
    at readableAddChunk (_stream_readable.js:250:11)
    at TLSSocket.Readable.push (_stream_readable.js:208:10) code: 'EAUTH', command: 'API' }
/home/voidrealm/Desktop/myApp/controllers/emailController.js:32
                        console.log("email sent successfully", info.response)
                                                                    ^

TypeError: Cannot read property 'response' of undefined
    at transporter.sendMail (/home/voidrealm/Desktop/myApp/controllers/emailController.js:32:69)
    at transporter.send.args (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/mailer/index.js:226:21)
    at connection.login.err (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-transport/index.js:282:36)
    at SMTPConnection.login (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:448:24)
    at connection.connect (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-transport/index.js:271:32)
    at SMTPConnection.once (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:215:17)
    at Object.onceWrapper (events.js:313:30)
    at emitNone (events.js:106:13)
    at SMTPConnection.emit (events.js:208:7)
    at SMTPConnection._actionEHLO (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:1313:14)
    at SMTPConnection._processResponse (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:942:20)
    at SMTPConnection._onData (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:749:14)
    at TLSSocket.SMTPConnection._onSocketData.chunk (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:195:44)
    at emitOne (events.js:116:13)
    at TLSSocket.emit (events.js:211:7)
    at addChunk (_stream_readable.js:263:12)

Обновление

После настройки OAuth я получаю ту же ошибку :

Вот мой обновленный код.

mailer. js

const nodemailer = require("nodemailer")

let transporter = nodemailer.createTransport({
    service: "gmail",
    auth: {
        type: "OAuth2",
        user: process.env.EMAIL,
        clientId: process.env.clientId,
        clientSecret: process.env.clientSecret,
        refreshToken: process.env.refreshToken,
        accessToken: process.env.accessToken,
        expiresIn: process.env.expiresIn
    }
})

getPasswordResetURL = (user, token) => {
    return `http://localhost:3000/reset-password/${user._id}/${token}`
}

const resetPasswordTemplate = (user, url) => {  
    from = process.env.EMAIL,
    to = user.email,
    subject = "Password Reset",
    auth = {
        user: user.email,
        refreshToken: process.env.refreshToken,
        accessToken: process.env.accessToken,
        expiresIn: process.env.expiresIn
    },
    html = `
        <p>We heard that you forgot your password. Sorry about that!</p>
        <p>But don’t worry! You can use the following link to reset your password:</p>
        <a href=${url}>${url}</a>
        <p>If you don’t use this link within 1 hour, it will expire.</p>
    `
    return {from, to, subject, html, auth}
}

module.exports = { transporter, getPasswordResetURL, resetPasswordTemplate }

emailController. js

const User = require("../models/User")
const bcrypt = require("bcrypt")
const jwt = require("jsonwebtoken")
const validator = require("validator")
const { transporter, getPasswordResetURL, resetPasswordTemplate } = require("../utils/mailer")

module.exports = {

    createResetPasswordTokenAndSendMail: (req, res) => {
        const email = req.params.email
            User.findOne({ email }, (err, user) => {
                if (err) console.log(err)
                // res.json({user})
                const hashedPassword = user.password
                const createdAt = user.createdAt
                const userId = user._id
                // console.log(user.password, user.createdAt, userId )
                const secret = hashedPassword + "-" + createdAt 
                const token = jwt.sign({ userId }, secret, {
                    expiresIn: 3600
                })
                // console.log(token)
                // console.log(user)
                const url = getPasswordResetURL(user, token) 
                // console.log(url)
                const emailTemplate = resetPasswordTemplate(user, url)
                console.log(emailTemplate, "l26")

                const sendEmail = () => {
                    transporter.sendMail(emailTemplate, (err, info) => {
                        if (err) console.log(err)
                        // console.log(info, "L31")
                        console.log("email sent successfully", info.response)
                    })
                }
                sendEmail()
        })
    }
}

Консоль

{ Error: invalid_request
    at postRequest (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/xoauth2/index.js:259:33)
    at PassThrough.req.once (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/xoauth2/index.js:328:20)
    at Object.onceWrapper (events.js:313:30)
    at emitNone (events.js:111:20)
    at PassThrough.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1064:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9) code: 'EAUTH', command: 'AUTH XOAUTH2' }
/home/voidrealm/Desktop/myApp/controllers/emailController.js:33
                        console.log("email sent successfully", info.response)
                                                                    ^

TypeError: Cannot read property 'response' of undefined
    at transporter.sendMail (/home/voidrealm/Desktop/myApp/controllers/emailController.js:33:69)
    at transporter.send.args (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/mailer/index.js:226:21)
    at connection.login.err (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-transport/index.js:282:36)
    at _auth.oauth2.getToken (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/smtp-connection/index.js:1709:24)
    at generateCallback (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/xoauth2/index.js:111:13)
    at postRequest (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/xoauth2/index.js:259:24)
    at PassThrough.req.once (/home/voidrealm/Desktop/myApp/node_modules/nodemailer/lib/xoauth2/index.js:328:20)
    at Object.onceWrapper (events.js:313:30)
    at emitNone (events.js:111:20)
    at PassThrough.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1064:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)

Примечание : я получаю все значения учетных данных, необходимые для аутентификации, и сохранил их в моем файле .env .

Ответы [ 2 ]

0 голосов
/ 22 февраля 2020

Вы нигде не объявили перевозчика.

Попробуйте выполнить приведенный ниже код,

var transporter = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: process.env.EMAIL,
    pass: process.env.PASSWORD
  }
});

var mailOptions = {
  const from = process.env.EMAIL
    const to = user.email
    const subject = "Password Reset"
    const html = `
        <p>Hey` + user.name  user.email+`,</p>
        <p>We heard that you forgot your password. Sorry about that!</p>
        <p>But don’t worry! You can use the following link to reset your password:</p>
        <a href=`url`>`url</a>
        <p>If you don’t use this link within 1 hour, it will expire.</p>
    `
};

transporter.sendMail(mailOptions, function(error, info){
  if (error) {
    console.log(error);
  } else {
    console.log('Email sent: ' + info.response);
  }
});

EDITED
Измените формат html, как я делаю в приведенном выше коде.

0 голосов
/ 22 февраля 2020

Согласно этому ответу , службе электронной почты приложения Gmail / Google требуется OAuth2 для аутентификации. Для обычного текстового пароля потребуется отключить функции безопасности вручную в учетной записи Google.

Поэтому убедитесь, что вы отключили функции безопасности в своей учетной записи или используете oAuth2.

Кроме того, я не уверен, какая версия используемой Nodemail, но аргумент info не содержит response prop. Он имеет свойство envelope и messageId.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...