i'm building a management webapp for courses management. I have a mongodb with all my alumns , their email and their registration id. I wanna send the id to their mail. I have a html template and then with the fs.readfile and .replace() functions i replace the placeholders with the real infos i wanna send.
async function sendMail(mail,idreg){
var html_template;
const dataReg = "12/02/2019";
const oraReg = "16:00";
console.log(mail,idreg)
fs.readFile("./html_template/beefree-9o6bg29htfb.html",(err,data)=>{
html_template = data.toString().replace("XYZXYZXYZ",idreg).replace("XX/YY/ZZZZ",dataReg).replace("XX:YY",oraReg);
});
// Generate test SMTP service account from ethereal.email
// Only needed if you don't have a real mail account for testing
let account = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true, // true for 465, false for other ports
auth: {
user: "mymail#gmail.com ", // generated ethereal user
pass: "mypw" // generated ethereal password
}
});
// setup email data with unicode symbols
let mailOptions = {
from: '"Cogestione Moscati" <mymail#gmail.com>', // sender address
to: mail, // list of receivers
subject: "Il tuo codice di registrazione per la Cogestione", // Subject line
html: html_template // html body
};
// send mail with defined transport object
let info = await transporter.sendMail(mailOptions)
console.log("Message sent: %s", info.messageId);
}
The problem is that i sent 8 times the same mail. 4 times i received correctly, 4 times i received with no body.
The code underneath your call to fs.readFile is not provided as part of the callback to that function. Basically, the file read is being kicked off and the rest of the code begins execution, resulting in a race to create html_template before the email is sent.
Two solutions:
Extend the callback to include the rest of the code. This would be the preferred method, as it is non-blocking and thus allows your application to continue serving other requests.
Use fs.readFileSync, the synchronous equivalent.
Also, since you are using async/await, you could also just let data = await fs.readFile("path/to/file");
Related
Before I go into this, I know two very common issues with Gmail with Nodemailer is that Allow Less Secure Apps is disabled by default, and I know two factor authentication can provide similar issues. Neither of these is the case.
I am attempting to make a system wherein many user accounts can be created en masse. When they are created, each account will receive an email with a greeting and their password. The issue was that gmail does not like spam, so the emails wouldn't send. I tried adding a 1 second wait period between each mutation thus between each email, but that didn't work either.
I now have a SendInBlue Account, using that same gmail. My code looks like this now...
////////////////////////////////
/// ///
/// EMAIL STUFF ///
/// ///
////////////////////////////////
// Creates the Transporter
const transporter = nodemailer.createTransport({
service: "SendinBlue",
auth: {
user: `${process.env.EMAIL_ADDRESS}`,
pass: `${process.env.EMAIL_PASSWORD}`
}
})
// Creates the Mail Object
const mailOptions = {
from: `${process.env.EMAIL_ADDRESS}`,
to: `${actualEmail}`,
subject: `Thank you for joining the TOM Team!`,
text: `We have recieved your Account Signup and are please to welcome you to the TOM Experience!`
}
// Sends the mail
transporter.sendMail(mailOptions, (error, response) => {
if (error){
throw new Error('Something went wrong, please try again \n' + error)
}
})
Wherein the only thing in the code above that is different than when it was sending (or at least it was trying to send before it got hit with the spam block) is the line service: "SendinBlue", was changed from service: "Gmail",
Is this an issue with SendInBlue, or does this look more like a Gmail / Nodemailer issue? Could anyone assist
I'm trying to send some E-mails using nodemailer module.
here is my program:
const nodeMailer = require('nodemailer');
const randomSentence = require('random-sentence');
let mailList = [
'gmans8951#gmail.com',
'hamideh.2020ha#gmail.com',
'mali1370.goli#gmail.com',
'golgolniamilad#gmail.com'
]
async function test(){
let transporter = nodeMailer.createTransport({
host: 'smtp.mail.yahoo.com',
port: '465',
secure: true,
auth: {
user: 'milad1395#yahoo.com',
pass: 'xxxxxxxxxxx'
}
});
try{
for (let index = 0; index < mailList.length; index++) {
let mailBody = randomSentence();
console.log(mailBody);
const contact = mailList[index];
await transporter.sendMail({
from: 'Node Mailer Test App <milad1395#yahoo.com>',
to: contact,
subject: 'test',
html: mailBody
})
}
console.log('All mails sent successfully!');
}catch(err){
console.log(`Error: ${err}`);
}
}
let forCount = 1;
for (let index = 0; index < forCount; index++) {
test();
}
If I run this program, It works fine:
$ node debug.js
message 0: Ecmiw perpef suchuf runog olu duiduz remis ehere bevu fetuh leh areri gujin kuvug bifa.
message 1: Tuemigo lelsojkil we fenob meboceuti rifa ci ewiilu fisif uwois apovev seplep kotpi voug vek.
message 2: Suvne goeviru gigiwo dec pitak daiwa edo fifmij ne lad osezo wilomdo ore kebpenu nig zifvi gocpo.
message 3: Kibep pevkih cuf jar du lu li loj gicrioke fuwdij fo fo tiho pupaj pogpisu vogo uja.
All mails sent successfully!
But if I increase the forCount variable to 2, it will send some of emails but then I'll get below error:
Error: Error: Message failed: 554 6.6.0 Error sending message for delivery.
Question 1: Why does this error happen?
Question 2: How to resolve this issue?
Finally I found answer of my question:)
It seems this problem is associated with Yahoo servers and not my code. Maybe Yahoo uses an aggressive filtering algorithm to decrease traffic over it's servers.
By the way if you face this problem too, I advise you to migrate to another delivery provider(e.g. Gmail).
Don't be so hasty to blame Yahoo. Try adding logger and enable debug in the transport to print to console the full SMTP communication so that you can actually troubleshoot what the issue may be. See below transport.
One possible issue is you need to create an app password from your Yahoo account security page. I think this is required or you wont be able to authenticate. An alternative is to play around with yahoo settings and find somewhere to allow insecure logins which will allow you to put in your normal password. I think Gmail has this somewhere too.
Anyway, I copied your code and modified it to only send a single message instead of 4. Works fine for me, likely because of the App Password I mentioned. Also works on port 587 just fine.
let transporter = nodeMailer.createTransport({
logger: true,
debug: true,
host: 'smtp.mail.yahoo.com',
port: 465,
secure: true, // true if using port 465 and then we want to STARTTLS, should be false if using port 587
auth: {
user: 'some_user#yahoo.com',
pass: 'create_app_pass_from_yahoo_security_page'
}
});
I'm trying to setup ZOHO mail with Nodemailer. The mail is configured correctly and I'm using following code to send the mail:
var transporter = nodemailer.createTransport({
host: 'smtp.zoho.eu',
port: 465,
secure: true, //ssl
auth: {
user:'info#myaddress.be',
pass:'supersecretpassword'
}
});
sendMail = function(req,res) {
var data = req.body;
transporter.sendMail({
from: data.contactEmail,
to: 'info#myaddress.be',
subject: data.contactSubject,
text: data.contactMsg
});
res.json(data);
};
I contacted official support but no response so far. Maybe someone here has experience with it. The problem is that when using these settings I get a message that relaying is disallowed for the address in variable 'data.contactEmail'. When I change the from e-mail also to info#myaddress.be I do receive the e-mail but of course I do not know who sent it and can't reply to it.
Anyone who knows how to make the 'from' address work with unknown addresses? Like john#gmail.com ?
Solution :
You should make an email account for your server : bot#myaddress.be
When you are going to relay the mail craft a custom MAILBODY containing the subject and message
var MAILBODY ='\n[suject]:\n'+data.contactSubject+'\n\n[msg]:\n'+data.contactMsg;
So you will be sending the original contactEmail as the subject of the mail and using the mail's text (body) to se the message subject and the message content.
transporter.sendMail({
from: 'bot#myaddress.be',
to: 'info#myaddress.be',
subject: data.contactEmail,
text: MAILBODY
});
Reason of Solution :
Example bot account will be able of sending the email to yourself with all the details you really need. (because you control that email account / your domain)
The credentials you are providing are for your OWN account and you are trying to send an email FROM an unknown account. This might only be possible if you had the credentials for the unknown account (given that they have allowed open access to other clients/apps).
You simply can not send an email on behalf of an account you do not have credentials for.
Im trying to implement some code that sends an email to anyone who would like to sign up to my newsletter. The code is actually working, but it sends multiple duplicates. Im using Firebase' samplecode, like this.
I think the problem is that it listensens for every change on the {uid} and I'm setting 4 values. If I manually change anything at the database from the dashboard, it triggers the event and sends a new mail. My code:
'use strict';
const functions = require('firebase-functions');
const nodemailer = require('nodemailer');
// Configure the email transport using the default SMTP transport and a GMail account.
// For other types of transports such as Sendgrid see https://nodemailer.com/transports/
// TODO: Configure the `gmail.email` and `gmail.password` Google Cloud environment variables.
const gmailEmail = encodeURIComponent(functions.config().gmail.email);
const gmailPassword = encodeURIComponent(functions.config().gmail.password);
const mailTransport = nodemailer.createTransport(
`smtps://${gmailEmail}:${gmailPassword}#smtp.gmail.com`);
// Sends an email confirmation when a user changes his mailing list subscription.
exports.sendEmailConfirmation = functions.database.ref('/mailingList/{uid}').onWrite(event => {
const snapshot = event.data;
const val = snapshot.val();
if (!snapshot.changed('subscribed')) {
return;
}
const mailOptions = {
from: '"Spammy Corp." <noreply#firebase.com>',
to: val.email
};
// The user just subscribed to our newsletter.
if (val.subscribed == true) {
mailOptions.subject = 'Thanks and Welcome!';
mailOptions.text = 'Thanks you for subscribing to our newsletter. You will receive our next weekly newsletter.';
return mailTransport.sendMail(mailOptions).then(() => {
console.log('New subscription confirmation email sent to:', val.email);
});
}
});
A database trigger will run for each change made to the path it's monitoring, and you need to plan for that. In your function, you need a way to figure out if the email has already been sent. The typical solution is to write a boolean or some other flag value back into the node that triggered the change, then check for that value every time and return early if it's set.
I am using node.js 's email module nodemail and sendgrid API to send the email to the users.
Here is my code for sending a email
SOURCE_EMAIL = ?????;
var options = {
auth: {
api_user: sendgrid.api,
api_key: sendgrid.key
}
};
transport = nodemailer.createTransport(sgTransport(options));
transport.sendMail({from: SOURCE_EMAIL, to: email, subject: subject, html: html}, function(err,data){
});
my question is when I use the sendgrid API to send email, what SOURCE_MAIL i should configure to ?
You may set SOURCE_EMAIL to anything you want.
It's best to set it to an email you own, control, and can receive email from.
However, it's entirely up to you.