Currently I am able to send emails in node.js using code along the lines of:
var nodemailer = require("nodemailer");
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "gmail.user#gmail.com",
pass: "gmailpass"
}
});
smtpTransport.sendMail({
from: "My Name <me#example.com>", // sender address
to: "Your Name <you#example.com>", // comma separated list of receivers
subject: "Hello ✔", // Subject line
text: "Hello world ✔" // plaintext body
}, function(error, response){
if(error){
console.log(error);
}else{
console.log("Message sent: " + response.message);
}
});
How can I send an attachment of an uploaded image from an html form in this email? Also, can I send the image in the email without uploading it to the serve? If not, that's okay. This is my html form:
<form id="mainForm">
<input type="file" id="fileUpload">
<input type="submit" id="submit" name="submit">
</form>
How can I take the file and include it in the email I send using node.js?
You could try something like this. Use busboy to get the file and then once you get the file convert it to base64 and add it to the attachment property for you mail options. The only thing is i dont know if the file argument comes back as a buffer. If it doesnt you just need to convert that file to base 64 and will be able to send it as an attachement
var app = express();
var Busboy = require('busboy');
var nodemailer = require("nodemailer");
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "gmail.user#gmail.com",
pass: "gmailpass"
}
});
app.post('/email', function(req, res){
var busboy = new Busboy({ headers: req.headers });
var attachments = [];
var mailOptions = {
from: "My Name <me#example.com>", // sender address
to: "Your Name <you#example.com>", // comma separated list of receivers
subject: "Hello ✔", // Subject line
text: "Hello world ✔" // plaintext body
};
busboy
.on('file', function(fieldname, file, filename, encoding, mimetype){
attachments.push({
filename: filename,
content: file.toString('base64'),
encoding: 'base64'
});
})
.on('finish', function() {
mailOptions.attachments = attachments;
smtpTransport.sendMail(mailOptions, function (err, info) {
if (err) {
//handle error
}
// email sent
});
});
});
Related
I'm trying to add a contact form in my website using nodemailer.
With plain-text, the email was sent (with the cmd node server.js), but since I have added a form in my html and tried to send the "req.bodies" using a route, it doesn't work anymore and I have the following error : Error: Missing credentials for "PLAIN".
Here are my codes :
Index.js
var express = require("express");
var router = express.Router();
const nodemailer = require("nodemailer");
/* GET home page. */
router.get("/", function (req, res, next) {
res.render("index", { title: "Express" });
});
router.post("/send-email", async function (req, res, next) {
"use strict";
var email = req.body.email;
var name = req.body.name;
var message = req.body.message;
var transporter = nodemailer.createTransport({
// host: "smtp.gmail.com",
service: "gmail",
// secure : false,
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD,
},
});
console.log("message :", req.body.message, "email :", req.body.email);
// send mail with defined transport object
var mailOptions = {
from: email,
to: process.env.EMAIL,
subject: "Nouveau mail contact de " + name, // Subject line
text: name + "0102030405" + message,
};
transporter.sendMail(mailOptions, function (error, response) {
if (error) {
console.log(error);
} else {
res.redirect("/");
}
});
});
module.exports = router;
Server.js
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const port = 3000;
require("dotenv").config();
app.use(bodyParser.json());
const nodemailer = require("nodemailer");
app.listen(port, () => {
console.log(`Server running on ${port}`);
});
app.use("/index", require("./routes/index"));
// let transport = nodemailer.createTransport({
// service: "gmail",
// auth: {
// user: process.env.EMAIL,
// pass: process.env.PASSWORD,
// },
// });
// let mailOptions = {
// from: '"Fred Foo 👻" <process.env.EMAIL>', // sender address
// to: "process.env.EMAIL", // list of receivers
// subject: "Hello ✔", // Subject line
// text: "Hello world?", // plain text body
// html: "<b>Hello world?</b>", // html body
// };
// transport.sendMail(mailOptions, function (err, data) {
// if (err) {
// console.log("Error Occurs");
// } else {
// console.log("Email sent !!");
// }
// });
html
<form action="/send-email" method="POST">
Your Name:
<input type="text" name="name">
Email Address:
<input type="email" name="email" placeholder="Email">
Message:
<textarea name="message"></textarea>
<input type="submit" value="Submit">
</form>
Body-Parser doesn't seem to work because it is strikeout.
“less secure” apps is enabled on my gmail account
Thank you very much for your help !
EDIT : I think it's because it doesn't recognize my process.env because when I directly write them, it works.
I put my file .env in the same directory but it still does not recognize them.
I am trying to send emails through nodemailer, and I've used it multiple times with my gmail account... the problem is, I don't want to use my gmail account now, and I want to use my business email so I could send out emails to clients on a regular...
I have it set up like this right now, but not sure how to do it without gmail / smtp:
app.post('/sendBatchEmail', (req, res) => {
var emails = [];
var emailSubject = req.body.emailSubject;
var emailMessage = req.body.emailMessage;
//perform db2 send
var sendEmail = "select * from testEmails"
ibmdb.open(ibmdbconnMaster, function (err, conn) {
if (err) return console.log(err);
conn.query(sendEmail, function (err, rows) {
if (err) {
console.log(err);
}
for (var i = 0; i < rows.length; i++) {
emails.push(rows[i].EMAIL)
}
//send email
async function main() {
// Generate test SMTP service account from ethereal.email
// Only needed if you don't have a real mail account for testing
let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "x",
pass: "x",
},
});
// send mail with defined transport object
let sendBatch = await transporter.sendMail({
from: "", // sender address
to: "xxxxx#gmail.com",
bcc: emails, // list of receivers
subject: emailSubject, // Subject line
text: emailMessage, // plain text body
});
console.log("Message sent: %s", sendBatch.messageId);
}
main().catch(console.error);
res.redirect("/index");
conn.close(function () {
console.log("closed the function app.get(/account)");
});
});
});
I am not sure how to not use smtp server so I can use biz email, or even if this is possible! Thanks in advance for help :)
})
As you can do this using nodemailer, but sending an email without a SMTP is not recommended as there are much higher chances of being rejected or put into spam folder. I'm pretty sure gmail like services will put the emails in Spam folder. here is how you can implement it:
let transporter = nodemailer.createTransport({
host: "smtp.example.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "x",
pass: "x",
},
});
// send mail with defined transport object
let sendBatch = await transporter.sendMail({
from: "<foo#example.com>", // sender address
to: "xxxxx#gmail.com",
bcc: emails, // list of receivers
subject: emailSubject, // Subject line
text: emailMessage, // plain text body
});
console.log("Message sent: %s", sendBatch.messageId);
}
For more details you can check here1 and here2
I am using nodemailer along with handlebars in my node project. The email is working fine but I am not able to attach image in the html template created by handlebars. I tried giving it in img src tag directly in the html but still not working. What i have is that the image is in svg form and in my assets folder of the project.
I also tried the example on the official nodemailer site which did not work as well. Please help me out!
https://nodemailer.com/message/embedded-images/
This is my function which will be called when I get the request from the client.
sendEmail.js
var nodemailer = require("nodemailer");
const emailConfig = require("../readEmailConfigFile");
//reading username and password from json file
let fromemail = emailConfig.readFromEmail();
let password = emailConfig.readFromPassword();
var handlebars = require("handlebars");
var fs = require("fs");
const readHTMLFile = function(path, callback) {
fs.readFile(path, { encoding: "utf-8" }, function(err, html) {
if (err) {
throw err;
callback(err);
} else {
callback(null, html);
}
});
};
/* Method for sending Email */
const sendEmail = (details) => {
var transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: fromemail,
pass: password
}
});
readHTMLFile(
__dirname + "/../emailTemplates/EmailTemplate.html",
function(err, html) {
var template = handlebars.compile(html);
var replacements = {
firstName: details.firstName,
lastName: details.lastName,
address: details.address,
};
var htmlToSend = template(replacements);
var mailOptions = {
from: fromemail,
to: details.email,
subject: "ABC",
html: htmlToSend
};
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
console.log(error);
callback(error);
} else {
console.log("Email Sent : " + info.response);
}
});
}
);
};
This is my html-template file
EmailTemplate.html
<html>
<head>
<title> </title>
</head>
<body>
<p>
Dear {{{firstName}}} {{{lastName}}}, your address is {{{address}}}</span
>
</p>
</body>
</html>
I want to embed an svg image in this html!
just add attachments parameter to your mailoptions object :
var mailOptions = {
from: fromemail,
to: details.email,
subject: "ABC",
attachments: [{
filename: 'imagename.svg',
path: __dirname +'/assets/imagename.svg',
cid: 'imagename'
}],
html: htmlToSend
};
then add the img tag in your HTML <img src="cid:imagename">
I know how to send mail using nodemailer but I am using email credentials of that, but I don't want to use that. Is there any other method of sending mails.
My nodemailer code snippet is
var nodemailer = require('nodemailer');
// Not the movie transporter!
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'vikaskohli#email.com', // Your email id
pass: 'password' // Your password
}
});
module.exports =
{
sendEmail: function sendMail(varhtml,vartext, varsubject,varfrom, varfrom_name,varto, varto_name, reply_to_email ) {
//setup e-mail data with unicode symbols
var mailOptions = {
from: varfrom_name, // sender address
// to: ['vikaskohli#email.com','vikaskohli1#email.com'], // list of receivers
// to: ['vikaskohli#email.com,vikaskohli1#email.com'], // list of receivers
// to: 'vikaskohli#email.com','vikaskohli1#email.com', // list of receivers
to: varto, // list of receivers
subject: varsubject, // Subject line
text: vartext, // plaintext body
html: varhtml // html body
};
console.log(mailOptions);
// send mail with defined transport object
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
return console.log(error);
}else{
return console.log(info);
}
});
}
}
In the above code, also I don't change my sender name. If I want to send from other mail like
vikaskohli3#gmail.com
but it automatically send from that mail for which I have use credentials here
vikaskohli#email.com
Also I tried using sendmail npm, they don't need any credentials but it send mail in the spam folder
My sendmail code snippet
var sendmail = require('sendmail')({silent: true})
sendmail({
from: 'vikaskohli#email.com',
to: 'vikaskohli#email.com,vikaskohli1#email.com',
subject: varsubject, // Subject line
html: varhtml,
attachments: [
]
}, function (err, reply) {
console.log(err && err.stack)
console.dir(reply)
});
I use sendmail like your bottom code, and it works fine for me. Perhaps the reason it's going to spam is because your settings in the email provider. Most likely the email you chose as sender (#email.com) seems like a spam to that service provider or your settings.
I want to send email with nodemailer using html template. In that template I need to inject some dynamically some variables and I really can't do that. My code:
var nodemailer = require('nodemailer');
var smtpTransport = require('nodemailer-smtp-transport');
smtpTransport = nodemailer.createTransport(smtpTransport({
host: mailConfig.host,
secure: mailConfig.secure,
port: mailConfig.port,
auth: {
user: mailConfig.auth.user,
pass: mailConfig.auth.pass
}
}));
var mailOptions = {
from: 'my#email.com',
to : 'some#email.com',
subject : 'test subject',
html : { path: 'app/public/pages/emailWithPDF.html' }
};
smtpTransport.sendMail(mailOptions, function (error, response) {
if (error) {
console.log(error);
callback(error);
}
});
Let's say I want in emailWithPDF.html something like this:
Hello {{username}}!
I've found some examples, where was smth like this:
...
html: '<p>Hello {{username}}</p>'
...
but I want it in separate html file. Is it possible?
What you can do is read the HTML file using fs module in node and then replace the elements that you want changed in the html string using handlebars
var nodemailer = require('nodemailer');
var smtpTransport = require('nodemailer-smtp-transport');
var handlebars = require('handlebars');
var fs = require('fs');
var readHTMLFile = function(path, callback) {
fs.readFile(path, {encoding: 'utf-8'}, function (err, html) {
if (err) {
callback(err);
}
else {
callback(null, html);
}
});
};
smtpTransport = nodemailer.createTransport(smtpTransport({
host: mailConfig.host,
secure: mailConfig.secure,
port: mailConfig.port,
auth: {
user: mailConfig.auth.user,
pass: mailConfig.auth.pass
}
}));
readHTMLFile(__dirname + 'app/public/pages/emailWithPDF.html', function(err, html) {
if (err) {
console.log('error reading file', err);
return;
}
var template = handlebars.compile(html);
var replacements = {
username: "John Doe"
};
var htmlToSend = template(replacements);
var mailOptions = {
from: 'my#email.com',
to : 'some#email.com',
subject : 'test subject',
html : htmlToSend
};
smtpTransport.sendMail(mailOptions, function (error, response) {
if (error) {
console.log(error);
}
});
});
I use it in all my projects. more clean and up to date and understandable. callback hell doesn't exist.
sendMail.ts The html file reads with handlebar, puts the relevant variables into the contents, and sends.
import * as nodemailer from 'nodemailer';
import * as handlebars from 'handlebars';
import * as fs from 'fs';
import * as path from 'path';
export async function sendEmail(email: string, subject: string, url: string) {
const __dirname = path.resolve();
const filePath = path.join(__dirname, '../emails/password-reset.html');
const source = fs.readFileSync(filePath, 'utf-8').toString();
const template = handlebars.compile(source);
const replacements = {
username: "Umut YEREBAKMAZ"
};
const htmlToSend = template(replacements);
const transporter = nodemailer.createTransport({
host: "smtp.mailtrap.io",
port: 2525, // 587
secure: false,
auth: {
user: "fg7f6g7g67",
pass: "asds7ds7d6"
}
});
const mailOptions = {
from: '"noreply#yourdomain.com" <noreply#yourdomain.com>',
to: email,
subject: subject,
text: url,
html: htmlToSend
};
const info = await transporter.sendMail(mailOptions);
console.log("Message sent: %s", info.messageId);
console.log("Preview URL: %s", "https://mailtrap.io/inboxes/test/messages/");
}
String replace isn't a good idea because you'll have to restore old strings or create a backup file to be able to change them another time, also it won't be asynchrone and it will cause a problem in every way!
you can do it much easier and more cleaner:
just go to your mail options and add context with your variables:
var mailOptions = {
from: 'nginx-iwnl#gmail.com',
to: 'username#gmail.com',
subject: 'Sending email',
template: 'yourTemplate',
context: { // <=
username: username,
whatever: variable
}
};
next thing to do is openning your html file and call your variables like:
{{username}}
If you're using Nodemailer 2.0.0 or higher, check this documentation:
https://community.nodemailer.com/2-0-0-beta/templating/ There they explain how to make use of external rendering with templates like that:
// external renderer
var EmailTemplate = require('email-templates').EmailTemplate;
var send = transporter.templateSender(new EmailTemplate('template/directory'));
They also give this example:
// create template based sender function
// assumes text.{ext} and html.{ext} in template/directory
var sendPwdReminder = transporter.templateSender(new EmailTemplate('template/directory'), {
from: 'sender#example.com',
});
where you see how to pass variables.
You will need the email-templates module: https://github.com/crocodilejs/node-email-templates and a template engine of your choice.
Also in the documentation of email-templates you'll find how to make your file structure in order that your templates can be found:
html.{{ext}} (required) - for html format of email
text.{{ext}} (optional) - for text format of email style.
{{ext}}(optional) - styles for html format subject.
{{ext}}(optional) - for subject of email
See supported template engines for possible template engine extensions (e.g. .ejs, .jade, .nunjucks) to use for the value of {{ext}} above.
You may prefix any file name with anything you like to help you identify the files more easily in your IDE. The only requirement is that the filename contains html., text., style., and subject. respectively.
Create one file emailTemplates.js there yo can store each template as a function
emailTemplates.js
const newsLetterEmail = (clientName) => `<p>Hi ${clientName}, here you have today news.</p>`
const welcomeEmail = (clientName, username) => `<p>Welcome ${clientName}, your username is ${username}.</p>`
export {newsLetterEmail, welcomeEmail}
Then in the controllers call any templateFunction and store in output varaible
controller.js
import {welcomeEmail} from './emailTeamplates.js'
const registerUser = async(req, res) => {
const {name, usename, email} = req.body
// User register code....
const output = welcomeEmail(name, username)
let mailOptions = {
from: '"Welcome" <welcome#welcome.com>',
to: 'client#gmail.com',
subject: 'Welcome email!',
text: 'Hello World',
html: output,
}
For those using pug as templating engine
Just a quick way to render a template in a separate file using pug's render function:
// function to send an e-mail. Assumes you've got nodemailer and pug templating engine installed.
// transporter object relates to nodemailer, see nodemailer docs for details
const nodemailer = require('nodemailer');
const pug = require('pug');
function send_some_mail(iterable){
var message = {
from: 'from#example.com',
to: 'to#example.com',
subject: 'Message title',
html: pug.renderFile(__dirname + 'path_to_template.pug', {iterable: iterable})
};
transporter.sendMail(message, function(err, info){...})
}
// template.pug
each item in iterable
li
p #{item.name}
See https://pugjs.org/api/getting-started.html for further details. Note that this will cause template re-compilation every time a message is sent. That is fine for occasional e-mail deliveries. If you send tons of e-mails, you can cache the compiled template to work around that. Check out pug docs for that set up if you need it.
You can use a Web Request to build an html template using handlebars or any other engine.
Create a template
First you must create an html template for the email body. In this example I used a handlebars hbs file.
Do your design stuff with html and add the variables that you will need in the message:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Welcome Email Template</title>
</head>
<body>
<p style="font-size: 14px; font-weight: normal;">Hi {{data.name}}</p>
</body>
</html>
Create a template request
You must create the access to this view. Then a request is created where we can send the template name as an url parameter to make the request parameterizable for other templates.
const web = express.Router()
web.post('/template/email/:template', function(req, res) {
res.render(`templates/email/${req.params.template}`, {
data: req.body
})
})
Mail function
Finally you can send the email after making the request to the template. You can use a function like the following:
const nodemailer = require('nodemailer')
const request = require("request")
function sendEmail(toEmail, subject, templateFile) {
var options = {
uri: `http://localhost:3000/template/email/${templateFile}`,
method: 'POST',
json: { name: "Jon Snow" } // All the information that needs to be sent
};
request(options, function (error, response, body) {
if (error) console.log(error)
var transporter = nodemailer.createTransport({
host: mailConfig.host,
port: mailConfig.port,
secure: true,
auth: {
user: mailConfig.account,
pass: mailConfig.password
}
})
var mailOptions = {
from: mailConfig.account,
to: toEmail,
subject: subject,
html: body
}
transporter.sendMail(mailOptions, function(error, info) {
if (error) console.log(error)
})
})
}
This can be done without templates.
Try changing it to this:
`Hello ${username}!`
Make sure that these are not inverted commas but back ticks.
There is one easy way to insert variable inside html in nodemailer.
html:"<p>Your message "+variable1+".Message continueous "+variable 2+"</p>"
You can also use async/await syntax or promises and avoid using callbacks, like I did here, using async/await:
const fs = require("fs").promises;
const path = require("path");
const handlebars = require("handlebars");
const relativeTemplatePath = "../../html/reset-pw-email-template.html";
function sendEmail(){
const templatePath = path.join(__dirname, relativeTemplatePath);
const templateFile = await fs.readFile(templatePath, 'utf-8');
const template = handlebars.compile(templateFile);
const replacements = {
username:""
};
const finalHtml = template(replacements);
const mailOptions = {
from: "",
to: "",
subject: "",
html: finalHtml,
};
}