英文:
TypeError: Cannot set properties of undefined (setting 'mailer')
问题
我正在尝试使用 nodemon(^2.0.22) 和 nodemailer(^6.9.3) 设置发送邮件。
原来,在尝试发送电子邮件时遇到此错误: "TypeError: Cannot set properties of undefined (setting 'mailer')",位于 nodemailer 库的 index.js 的第 45 行。访问此行时,我们有以下代码: this.transporter.mailer = this;
我无法确定是什么原因导致了这个错误。
谢谢。
英文:
I'm trying to set up an email sending using nodemon(^2.0.22) and nodemailer(^6.9.3).
It turns out that when trying to send the email I come across this error: "TypeError: Cannot set properties of undefined (setting 'mailer')" On line 45 of index.js of the nodemailer lib. When accessing this line, we have the following code: this.transporter.mailer = this;
I cannot identify what is causing this error. I'm going to pass here the HTML of my form, the header of my index.js and the route that sends the emails, so that you can help me.
Thanks.
HTML
<div id="tab2Content" class="tab-content">
<form id="formulario" action="/send" method="POST" role="form" enctype="Content-Type">
<div class="row">
<div>
<h2>Dados do solicitante</h2>
</div>
<div class="radio-container">
<label for="sigSim">Desejo não me identificar</label> <input type="radio" name="sigilo" id="sigSim" value="com_sigilo" required="" onchange="ocultarDivs()"> <br>
</div>
<div class="radio-container">
<label id="lblMaior" for="sigNao">Desejo me identificar, mostrando os meus dados</label> <input type="radio" name="sigilo" id="sigNao" value="sem_sigilo" required="" checked onchange="ocultarDivs()">
</div>
<br>
<br>
<fieldset id="dados_user">
<hr class="col-md-7 form-group mt-3 mt-md-0">
<div class="col-md-6 form-group">
<label for="name">Nome: </label>
<input type="text" name="name" class="form-control" id="name" placeholder="" >
</div>
<div class="col-md-6 form-group mt-3 mt-md-0">
<label for="email">E-mail: </label>
<input type="email" class="form-control" name="email" id="email" placeholder="" >
</div>
<div class="col-md-6 form-group mt-3 mt-md-0">
<label for="cep">CEP: </label>
<input type="text" class="form-control" name="cep" id="cep" value="" size="10" maxlength="9" onblur="pesquisacep(this.value);" placeholder="Digite apenas números" >
</div>
<div class="col-md-6 form-group mt-3 mt-md-0" id="rua_num">
<div id="div_ende" class="col-md-10">
<label for="endereco">Rua: </label>
<input type="text" class="form-control " name="endereco" id="rua" placeholder="" >
</div>
<div >
<label for="numero">N°: </label>
<input type="text" class="form-control " name="numero" id="numero" placeholder="" >
</div>
</div>
<div class="col-md-6 form-group mt-3 mt-md-0">
<label for="complemento">Complemento: </label>
<input type="text" class="form-control " name="complemento" id="complemento" placeholder="" >
</div>
<div class="col-md-6 form-group mt-3 mt-md-0">
<label for="bairro">Bairro: </label>
<input type="text" class="form-control" name="bairro" id="bairro" placeholder="" >
</div>
<div class="col-md-6 form-group mt-3 mt-md-0">
<label for="cidade">Cidade: </label>
<input type="text" class="form-control" name="cidade" id="cidade" placeholder="" >
</div>
<div class="col-md-6 form-group mt-3 mt-md-0">
<label for="uf">Estado: </label>
<input type="text" class="form-control" name="uf" id="uf" placeholder="" >
</div>
<!-- <div class="col-md-6 form-group mt-3 mt-md-0">
<label for="fixo">Telefone Fixo: </label>
<input type="tel" class="form-control" name="fixo" id="fixo" placeholder="" required="false">
</div> -->
<div class="col-md-6 form-group mt-3 mt-md-0">
<label for="celular">Telefone Celular: </label>
<input type="tel" class="form-control" name="celular" id="celular" placeholder="" >
</div>
</fieldset>
</div>
<br>
<hr class="col-md-7 form-group mt-3 mt-md-0">
<div class="form-group mt-6">
<div>
<h2>Dados da solicitação</h2>
</div>
<div class="col-md-7 form-group mt-3 mt-md-0">
<!-- alterar esse campo para lista de categoria: Solicitação, Elogio, Sugestão, Reclamação e Denúncia -->
<label for="categoria">Categoria: </label>
<select name="categoria" id="categoria" class="form-select-sm">
<option value="" disabled selected>Selecione uma categoria...</option>
<option value="Solicitação">Solicitação</option>
<option value="Reclamacao">Reclamação</option>
<option value="Denúncia">Denúncia</option>
<option value="Outros">Outros</option>
</select>
</div>
<br>
<fieldset id="dados_user">
<div class="col-md-7 form-group mt-3 mt-md-0" >
<label for="resposta" id="lblresposta">Como deseja receber a resposta: </label>
<!-- alterar esse campo para lista de como deseja receber a resposta: e-mail, carta, oficio, presencial, whatsapp, sem resposta -->
<select name="resposta" id="resposta" class="form-select-sm">
<option value="" disabled selected>Selecione uma resposta...</option>
<option value="E-mail">E-mail</option>
<option value="Ligação">Ligação</option>
<option value="Presencial">Presencial</option>
<option value="Whatsapp">Whatsapp</option>
<option value="Sem resposta">Sem Resposta</option>
</select>
</div>
</fieldset>
</div>
<br>
<hr class="col-md-7 form-group mt-3 mt-md-0">
<div class="form-group mt-3">
<div>
<h2>Mensagem</h2>
</div>
<div class="col-md-7 form-group mt-3 mt-md-0">
<label for="assunto">Assunto: </label>
<input type="text" class="form-control" name="assunto" id="assunto" placeholder="" required="">
</div>
<div class="col-md-7 form-group mt-3 mt-md-0">
<label for="arquivo">Arquivo: </label>
<input type="file" multiple accept=".jpg,.png,.jpeg,.bitmap,.doc,.docx,.pdf,.xls,.xlsx" class="form-control" name="arquivo" id="arquivo" placeholder="" >
</div>
<div class="col-md-7 form-group mt-3 mt-md-0">
<label for="mensagem">Mensagem: </label>
<textarea class="form-control" name="mensagem" id="mensagem" rows="7" placeholder="" required=""></textarea>
</div>
</div>
<br>
<input type="checkbox" id="lgpdCheckbox" name="lgpdCheckbox">
<label for="lgpdCheckbox">Li e concordo com os <a href="#" data-bs-toggle="modal" data-bs-target="#pdfModal">termos de consentimento da LGPD</a></label>
<br>
<br>
<div class="col-md-7 form-group mt-3 mt-md-0 text-center"><button id="enviar" name="btn_ouvidoria" value="ouvidoria" type="submit">Enviar mensagem</button></div>
</form>
</div>
the header of my index.js
// Importa o módulo express para esse arquivo
const express = require("express");
const { JSDOM } = require('jsdom');
const { url } = require("inspector");
const nodemailer = require('nodemailer')
const path = require("path");
const multer = require("multer")
const fs = require('fs');
const Swal = require('sweetalert2');
const ejs = require("ejs");
require("dotenv").config();
const FileType = require('file-type');
// Instancia uma referência do express no projeto
const app = express();
const bodyParser = require('body-parser');
const port = process.env.PORT || 5150; // Const para armanezar a porta do servidor
app.set("view engine", "ejs");
app.set('views', path.join(__dirname, 'views'));
const SMTPTransport = require("nodemailer/lib/smtp-transport");
app.use(express.urlencoded());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
const doc = dom.window.document;
const smtp = process.env.SMTP
const user_O = process.env.EMAIL_OUVIDORIA
const user_C = process.env.EMAIL_CONTATO
const pass = process.env.SENHA
const porta = process.env.PORTA
Route of send e-mail
app.post("/send", (req, res) =>{
app.use((err, req, res, next) => {
console.error(err);
res.status(500).send('Erro interno do servidor');
});
function procurarValor(x, lista) {
if (lista.includes(x)) {
return "Encontrado";
} else {
return "Não encontrado";
}
}
console.log('inicio do codigo')
const{name, email, cep, endereco, numero, complemento, bairro, cidade, uf, celular, categoria, resposta, assunto, mensagem} = req.body;
const btn = req.body.btn_ouvidoria;
console.log(req.body)
let recebedor = ""
let permissao = ""
let remetente = ""
console.log(user_O)
console.log(pass)
if (btn == "ouvidoria"){
console.log('acessou o if do btn ouvidoria')
recebedor = "ouvidoria@ezco.com.br";
permissao = req.body.sigilo;
const transporter = nodemailer.createTransport(
console.log('acessou a criação do transporter'),
new SMTPTransport({
host: smtp,
port: Number(porta),
auth: JSON.stringify({user: user_O, pass: pass})
}));
console.log('saiu do transporter');
console.log(transporter.host, transporter.port, transporter.user, transporter.pass, transporter.auth, transporter.secure)
transporter.verify(function(error, success) {
if (error) {
console.log('Erro na conexão SSL/TLS:', error);
} else {
console.log('Conexão SSL/TLS estabelecida com sucesso');
}
});
console.log('Final do id do btn ouvidoria')
// remetente = user_O;
} else if (btn === "fale_conosco"){
recebedor = "contato@ezco.com.br";
permissao = req.body.sigilo2;
const transporter = nodemailer.createTransport( new SMTPTransport({
host: smtp,
port: Number(465),
user: process.env.EMAIL_CONTATO,
pass: process.env.SENHA,
auth: {user, pass},
secure: true
}));
transporter.verify(function(error, success) {
if (error) {
console.log('Erro na conexão SSL/TLS:', error);
} else {
console.log('Conexão SSL/TLS estabelecida com sucesso');
}
});
// remetente = user_C;
}
console.log('começo da lista de cidades')
let cidades = [
'Abatiá',
'Andirá',
'Bandeirantes',
'Barra do Jacaré',
'Cambará',
'Carlópolis',
'Congonhinhas',
'Conselheiro Mairinck',
'Cornélio Procópio',
'Figueira',
'Guapirama',
'Ibaiti',
'Itambaracá',
'Jaboti',
'Jacarezinho',
'Japira',
'Joaquim Távora',
'Jundiaí do Sul',
'Leópolis',
'Nova América da Colina',
'Nova Fátima',
'Nova Santa Bárbara',
'Pinhalão',
'Quatiguá',
'Rancho Alegre',
'Ribeirão Claro',
'Ribeirão do Pinhal',
'Salto do Itararé',
'Santa Amélia',
'Santa Cecília do Pavão',
'Santa Mariana',
'Santana do Itararé',
'Santo Antônio da Platina',
'Santo Antônio do Paraíso',
'São Jerônimo da Serra',
'São José da Boa Vista',
'São Sebastião da Amoreira',
'Sapopema',
'Sertaneja',
'Siqueira Campos',
'Tomazina',
'Uraí',
'Wenceslau Braz'
]
console.log('final da lista de cidades')
// const anexo = req.files.map((arquivo) => ({
// filename: arquivo.originalname,
// path: arquivo.path,
// }));
// const totalSize = req.files.reduce((sum, file) => sum + file.size, 0);
// const limiteTamanho = 20 * 1024 * 1024; // 20MB
// Verifica se a soma dos tamanhos excede o limite
// if (totalSize > limiteTamanho) {
// Lidar com o limite excedido
// var exibirAlerta = true;
// res.render('ouvidoria', { exibirAlerta: exibirAlerta });
//apaga os arquivos que foram carregados
// req.files.forEach(arquivo => {
// fs.unlink(arquivo.path, (error) => {
// if (error) {
// console.error('Erro ao excluir o arquivo:', error);
// } else {
// console.log('Arquivo excluído com sucesso.');
// }
// });
// });
// return; // Encerra a função para evitar o envio do e-mail
// }
if (permissao == "com_sigilo" || permissao == "com_sigilo2"){
console.log('inicio do codigo com sigilo')
transporter.sendMail({
from: remetente,
to: recebedor,
subject: `${categoria}: ${assunto}`,
text:
`Mensagem: ${mensagem}`
// attachments: anexo,
}).then(info =>{
console.log('inicio do codigo then de envio')
// req.files.forEach(arquivo => {
// fs.unlink(arquivo.path, (error) => {
// if (error) {
// console.error('Erro ao excluir o arquivo:', error);
// } else {
// console.log('Arquivo excluído com sucesso.');
// }
// });
// });
res.render("confirmacao_sem_resp")
}).catch(error =>{
console.log('inicio do codigo catch de envio')
// req.files.forEach(arquivo => {
// fs.unlink(arquivo.path, (error) => {
// if (error) {
// console.error('Erro ao excluir o arquivo:', error);
// } else {
// console.log('Arquivo excluído com sucesso.');
// }
// });
// });
// res.send(error)
res.render("confirmacao_erro")
})
}else if (permissao == "sem_sigilo" || permissao == "sem_sigilo2"){
let resultado = procurarValor(`${cidade}`, cidades);
let regiao = ""
if (resultado = "Encontrado"){
regiao = "Norte Pioneiro"
}else{
regiao = "Sem região"
}
transporter.sendMail({
from: remetente,
to: recebedor,
replyTo: email,
subject: `${regiao} - ${categoria}: ${assunto}`,
text:
`Nome: ${name}
E-mail de contato: ${email}
CEP: ${cep}
Endereço: ${endereco}, ${numero} - ${complemento} - ${bairro} - ${cidade} - ${uf}
Telefone celular: ${celular}
Prefere que seja respondido via: ${resposta}
Mensagem: ${mensagem}`
// attachments: anexo,
}).then(info =>{
// req.files.forEach(arquivo => {
// fs.unlink(arquivo.path, (error) => {
// if (error) {
// console.error('Erro ao excluir o arquivo:', error);
// } else {
// console.log('Arquivo excluído com sucesso.');
// }
// });
// });
res.render("confirmacao_com_resp")
}).catch(error =>{
// req.files.forEach(arquivo => {
// fs.unlink(arquivo.path, (error) => {
// if (error) {
// console.error('Erro ao excluir o arquivo:', error);
// } else {
// console.log('Arquivo excluído com sucesso.');
// }
// });
// });
res.render("confirmacao_erro")
})
}
});
I've already searched the internet, in several places, including ChatGPT for the reason for this problem. Most of them point me to credential errors, however the credentials are set and checked.
答案1
得分: 2
我认为问题出在nodemailer.createTransport()的语法上。根据文档,无需将新的SMTPTransport作为参数传递。
预期的语法应该像这样:
nodemailer.createTransport({
pool: true,
host: "smtp.example.com",
port: 465,
secure: true, // 使用TLS
auth: {
user: "username",
pass: "password",
},
});
由于未能获取传输器,值将返回为undefined,因此this.transporter.mailer = this;将会中断,因为undefined没有"mailer"属性。
英文:
I think the problem is in the syntax of nodemailer.createTransport(). According to the documentation, there is no need to pass new SMTPTransport as an argument.
<br />
The expected syntax should look like this:
nodemailer.createTransport({
pool: true,
host: "smtp.example.com",
port: 465,
secure: true, // use TLS
auth: {
user: "username",
pass: "password",
},
});
By failing to retrieve a transporter, the values returns as undefined, and this.transporter.mailer = this; will break because undefined has no "mailer" attribute.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论