DRY code for sending email with SendGrid - javascript

I have this code inside a post route:
The first one is to alert my when a user register in my site:
sendgrid.send({
to: "my#email.com",
from: "myother#email.com",
subject: "[ALERT] " + req.body.eventDate,
html: "SOME HTML",
},
function(err, json) {
if (err) {
return console.error(err);
}
else {
next();
}
});
The next one is a confirmation email send to the new register member:
sendgrid.send({
to: req.body.email,
from: "my#email.com",
subject: "[CONFIRM] register" + req.body.eventDate,
html: "SOME HTML",
},
function(err, json) {
if (err) {
return console.error(err);
}
else {
next();
}
});
Is working 100%, but this is not a good practice, there is so much duplicate. Can i DRY this? If so, howww??
Thanks!!!

You can create a function which can perform the operation of sending emails using sendgrid like this,
function sendEmail(options) {
sendgrid.send(options,
function(err, json) {
if (err) {
return console.error(err);
}
else {
next();
}
});
}
And then you can utilise above created function as following,
For sending registration email
var registrationEmailOptions = {
to: "my#email.com",
from: "myother#email.com",
subject: "[ALERT] " + req.body.eventDate,
html: "SOME HTML",
}
sendEmail(registrationEmailOptions);
For sending confirmation email.
var confirmationEmailOptions = {
to: req.body.email,
from: "my#email.com",
subject: "[CONFIRM] register" + req.body.eventDate,
html: "SOME HTML",
}
sendEmail(confirmationEmailOptions);

Related

How do i add a sender name on send grid

The code below is my sendgrid helper function
presently, this is what comes up as the sender name "info" which is conned from infogmail.com. . i would like to add a custom name. i have read the docs but i have not seen a solution to my problem. all the solutions i saw was for python
const msg = {
to: email,
from: `${SENDER_EMAIL}`,
fromname: FROM_NAME,
subject: "Thanks for the Gift",
html: `${html(name, SENDER_EMAIL, SENDER_NAME)}`,
};
sgMail
.send(msg)
.then(() => {
console.log("Email sent");
})
.catch((error) => {
console.error(error);
});
};```
You can in this way:
sendgrid.send({
to: 'you#yourdomain.com',
from: {
email: 'example#example.com',
name: 'Sender Name'
},
subject: 'Hello World',
text: 'My first email through SendGrid'
});

Retry to send mail if not sent

I am using nodemailer to send emails through my node app. Sometimes Email does not work and throws an error until I try twice or thrice. I want my program to try again and again until the mail is successfully sent.
Here's my code:
const mailOptions = {
from: from,
to: client.email,
subject: 'Your Photos are ready',
html: mailTemplate
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
res.status(500).json({
message: "Mail not sent",
error
});
} else {
res.status(200).json({message: "Mail Sent", response: info.response});
}
});
How can I use the same function inside my if block?
Wrap sendMail in a function that returns a Promise
const promiseWrapper = mailOptions => new Promise((resolve, reject) => {
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
reject(error);
return;
}
resolve(info);
});
then in your route make the handler an async function and loop how many time that you want, then check if info exists if it does send 200 if not send 500
app.post('/sendmail', async (req, res) => {
let info;
let error;
for (let i = 0; i < 3; i++) {
try {
info = await promiseWrapper(mailOptions);
break;
} catch (e) {
error = e;
}
}
info
? res.status(200).json({ message: "Mail Sent", response: info.response })
: res.status(500).json({ message: "Mail not send", error }));
});
You can first separate the retry logic in a different file, so you can use it in various places.
Newer versions of nodemailer support promises for transporter.sendMail
// retry.js
// retries a function, called asynchronously, n amount of times
export async function retry(fn, n) {
for (let i = 0; i < n; i++) {
try {
return await fn()
} catch (err) {
console.log(err)
}
}
}
And pass the transporter function to the retry logic, with the amount of times you want to retry (in this example: 3)
import {retry} from '../utils/retry'
// ...
app.post('/sendmail', async (req, res) => {
try {
retry(
() =>
transporter.sendMail({
// your configuration
from: from,
to: client.email,
subject: 'Your Photos are ready',
html: mailTemplate
}),
3 // max retries
)
} catch (err) {
console.log(err)
// failed max retry times
res.sendStatus(500)
}
res.sendStatus(200)
})
const mailOptions = {
from: from,
to: client.email,
subject: 'Your Photos are ready',
html: mailTemplate
};
var i;
for(i = 0; i <= 1; i++) {
transporter.sendMail(mailOptions, function(error, info){
if (error) {
res.status(500).json({
message: "Mail not sent",
error
});
i = 0;
} else {
i = 2;
res.status(200).json({message: "Mail Sent", response: info.response});
}
});
}
Try the code above will run the function again and again if the error occur and it will exit the loop if no error occur.
Wrap it into a function and call in this way:
const mailOptions = {
from: from,
to: client.email,
subject: 'Your Photos are ready',
html: mailTemplate
};
function sendMail(mailOptions) {
transporter.sendMail(mailOptions, function(error, info){
if (error) {
return sendMail(mailOptions)
} else {
return res.status(200).json({message: "Mail Sent", response: info.response});
}
});
}
return sendMail(mailOptions);

node.js sending mails with a delay

I am doing a simple thing but that isn't working.
What I want to do is send mails with a delay of 30 seconds.
Here's the code:
user.forEach(function(data) {
var locals = {
fname: data.Name,
your_name: data.From,
}
template.render(locals, function(err, results) {
if (err) {
return console.error(err)
} else {
transporter.sendMail({
to: data.Email,
subject: "Welcome",
replyTo: data.ReplyTo,
html: results.html,
text: results.text,
}, function(error, info) {
console.log("here");
if (error) {
console.log(error);
} else {
console.log('Message sent: ' + info.response);
};
});
}
});
});
Here user is an array of objects with details like Email,from,Name etc.
Each object in array has details of a particular mail to be sent.
I want to send a mail and wait for 30s and then send the second one..and wait and so on.
I have used setInterval and also npm sleep, but that isn't working. It waits for 30s and then sends all mails at once.
You should replace syncronous forEach with asynchronous implementation.
Option1. Use async.js eachLimit and call callback with delay of 30 seconds
Option2. You can write wrapper for your send email function like:
var emails = ['email1', 'email2' /*...*/];
function sendEmailAndWait(email, callback){
// your stuff
transporter.sendMail(email, function(error, info) {
// handle results
if(!emails.length) return callback();
setTimeout(function () {
sendEmailAndWait(emails.shift(), callback);
}, 30*1000)
})
}
sendEmailAndWait(emails.shift(), function(){ /* allDone */});
setTimeout(function() {
template.render(locals, function(err, results) {
if (err) {
return console.error(err)
} else {
transporter.sendMail({
to: data.Email,
subject: "Welcome",
replyTo: data.ReplyTo,
html: results.html,
text: results.text,
}, function(error, info) {
console.log("here");
if (error) {
console.log(error);
} else {
console.log('Message sent: ' + info.response);
};
});
}
});
}, 3000);

Nodemailer's sendMail function returns "undefined"

Hi!
I have the following code. The commented lined never get executed and info.response returns "undefined". Could you help me figure out why it's returning "undefined" and why the commented parts don't get executed, please?
Thank you very much.
app.js:
app.get('/send', function (req, res) {
var mailOptions = {
from: req.query.from,
to: 'chul#stackexchange.com',
subject: 'Applicant',
text: req.query.name + req.query.content
};
console.log(mailOptions);
transport.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
res.end("error");
} else {
console.log("Message sent: " + info.repsonse);
res.end("sent"); // This part does NOT get executed.
};
});
});
index.html:
<script type='text/javascript'>
$(document).ready(function() {
var from, name, content;
$("#send_app").click(function() {
from = $("#from").val();
name = $("#name").val();
content = $("#content").val();
$("message").text("Submitting the application ...");
$.get("http://localhost:3000/send", {
from: from,
name: name,
content: content
}, function(data) {
if (data == "sent") { // This block does NOT get executed
console.log("sent received");
$("#message").empty().html("The e-mail has been sent.");
} else {
console.log(data);
}
});
});
});
</script>
From the looks of it, I don't see see the initialization of the transport. Try something like:
var transport = nodemailer.createTransport({
service: 'SendGrid',
auth: {
user: yourUserName,
pass: yourPassword
}
});
// Then the transport you initialized
var mailOptions = {
from: req.query.from,
to: 'chul#stackexchange.com',
subject: 'Applicant',
text: req.query.name + req.query.content
};
console.log(mailOptions);
transport.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
res.end("error");
} else {
console.log("Message sent: " + info.repsonse);
res.end("sent"); // This part does NOT get executed.
};
});

I can't handle 'error message' on a POST method which comes from controller

I've been trying to handle a responded error message with jQuery on Sails.
I'm using a js file(login.js) to login website and using another js file named SessionController to hold my logic code.
Firstly, a jquery POST method in my login.js file is sending a request.
Secondly, deliberately, i'm trying to enter wrong username or password. But I can't handle error messages in the POST method.
The below codes return 'Forbidden' as error parameter and 'null' as xhr.getResponseHeader('error'). But I've expected "Username error" or "Password error".
What should I do? I'm open to advices...
My login.js file
$(document).ready(function(){
$("#btn-login").click(function() {
var username = $("#username").val();
var password = $("#password").val();
if(!username) {
} else if(!password) {
} else {
// alert('It"s continuing to POST');
$.post(
'/login',
{ username: username, password: password },
function() {
window.location = "/user/show/"
}).fail(function(xhr, textStatus, error){
alert('xhr.statusText: ' + xhr.statusText);
alert('textStatus: ' + textStatus);
alert('error: ' + error);
// $("#popupPaddedMessage").text("Error: " + xhr.getResponseHeader('error'));
// $("#popupPadded").popup("open", { positionTo: "window" });
});
}
});
});
My SessionController js file
module.exports = {
create: function(req, res, next) {
User.native(function(err, collectionUser) {
if(err) { return err; };
if(!collectionUser) { return err; };
collectionUser
.find({'username' : req.param('username')})
.nextObject(function (err, user) {
if(err) {
res.send(500, { error: "Database error"});
};
if(!user) {
res.send(400, { error: "Username error"});
};
if(user) {
if(user.password === req.param('password')) {
req.session.user = user;
res.send(user);
//res.redirect('/user/show/' + user[0]._id);
} else {
res.send(400, { error: "Password error"});
}
};
});
});
}
};

Categories

Resources