I'm following this tutorial to send embedded images in SendGrid.
SendGrid
I cannot get the image to load in SendGrid.
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: 'somemail#gmail.com', // Change to your recipient
from: 'company#company.com', // Change to your verified sender
subject: 'SendGrid',
html: `<strong>Some Text ${Date.now()}</strong><div style="border:10px solid blue;"><img src="cid:image123" alt="test image"/></div>`,
files: [
{
filename: 'image.jpg',
contentType: 'image/jpeg',
cid: 'image123',
content: `https://i.picsum.photos/id/1069/536/354.jpg?hmac=ywdE7hQ_NM4wnxJshRkXBsy-MHlGRylyqlb51WToAQA`,
disposition: 'inline',
},
],
};
sgMail
.send(msg)
.then((res) => {
console.log(res);
})
.catch((error) => {
console.error(error);
});
I also tried it with a base 64 string
const buf = '_9j_4AAQSkZJRgABAQAASABIAAD_4QguRXhpZgAATU0AKgAAAAgADAEPAAIAAAAGAAAAngEQAAIAAAAJAAAApAESAAMAAAABAAEAAAEaAAUAAAABAAAArgEbAAUAAAABAAAAtgEoAAMA.....
...
content: `data:image/png;base64,${buf}`,
Zoho & Nodemailer
However the image does load using Nodemailer so I don't think it's gmail that's causing the issue.
I able to get inline images to show when using nodemailer with zoho:
const nodemailer = require('nodemailer');
try {
const transporter = nodemailer.createTransport({
host: 'smtp.zoho.com',
port: 587,
secure: false,
auth: {
user: <zoho_user>,
pass: <zoho_password>,,
},
});
const options = {
from: 'Company Name <company#company.com>',
to: 'someemail#gmail.com',
subject: 'Zoho email',
html: `<strong>Some Text ${Date.now()}</strong><img style="border: 10px solid orange;" src="cid:image123" />`,
attachments: [
{
filename: 'image.png',
path:
'https://i.picsum.photos/id/1069/536/354.jpg?hmac=ywdE7hQ_NM4wnxJshRkXBsy-MHlGRylyqlb51WToAQA',
cid: 'image123',
},
],
};
const sendZoho = async () => {
return await new Promise((res, rej) =>
transporter.sendMail(options, (error, info) => {
if (error) rej(error);
else res(info);
transporter.close();
})
);
};
const res = await sendZoho();
How can I send inline images to gmail with SendGrid?
I am trying to send a GMAIL message containing a PDF file (I am using nodemailer for this).
The error is generated when reading the PDF file with path (native dependency of node); The error that returns is a 500 Server Error.
module.exports.get_boletin = async (event) => {
const { wrapedSendMail } = require('./helpers/sendPromise');
const path = require('path');
const { email } = JSON.parse(event.body);
if(!email) {
return {
statusCode: 400,
body: JSON.stringify({
ok: false,
detail: 'Email is required'
})
};
}
const mailOptions = {
to: email,
from: "example#gmail.com",
subject: `any_msg`,
attachments: [
{
filename: `file.pdf`,
path: path.join(__dirname, `file.pdf`),
contentType: 'application/pdf',
},
],
}
const _send = await wrapedSendMail(mailOptions)
if(_send){
return {
statusCode: 200,
body: JSON.stringify({
ok: true,
detail: 'Mensaje enviado correctamente.',
event: JSON.parse(event.body)
})
}
} else {
return {
statusCode: 500,
body: JSON.stringify({
ok: false,
detail: 'Error al enviar el mensaje.',
event: JSON.parse(event.body)
})
}
}
};
This piece of code is the one that generates the error
attachments: [
{
filename: `file.pdf`,
path: path.join(__dirname, `file.pdf`),
contentType: 'application/pdf',
},
]
I tried locally and in an EC2 instance, this works normally the error is only generated in Lambda
I'm using Sendgrid to send a transactional Email with Firebase Cloud Functions using Nodejs.
const attachment = file.createReadStream();
const msg = {
to: email,
from: "test#test.com",
subject: "print order",
templateId: "templateid",
dynamic_template_data: {
dashboardurl: `/order#${orderId}`,
downloadurl: orderData.downloadurl
},
attachments: [{
content: attachment,
filename: "order.pdf",
type: "application/pdf",
disposition: "attachment"
}]
};
await sgMail.send(msg);
The Email won't send, because of the following bug:
TypeError: Converting circular structure to JSON
Solution for Firebase Storage
const tempFilePath = path.join(os.tmpdir(), "tmp.pdf");
await file.download({ destination: tempFilePath });
const attachment = fs.readFileSync(tempFilePath, { encoding: "base64" });
According to doc:
For content you send base64 encoded version of the file.
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: 'recipient#example.org',
from: 'sender#example.org',
subject: 'Hello attachment',
html: '<p>Here’s an attachment for you!</p>',
attachments: [
{
content: 'Some base 64 encoded attachment content',
filename: 'some-attachment.txt',
type: 'plain/text',
disposition: 'attachment',
contentId: 'mytext'
},
],
};
So in your case below conversion would suffice:
const attachment = fs.readFileSync('filepath', { encoding: 'base64' });
I want to send HTML mail with some images.
I am using the library called 'sendgrid-nodejs'.
However, I can not do that and find any documentation related to it.
My Code.
const fs = require('fs');
function base64_encode(file) {
var bitmap = fs.readFileSync(file);
return new Buffer(bitmap).toString('base64');
};
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: 'to address',
from: 'from address',
subject: 'subject',
html: '<strong>Some Text</strong><img src="cid:12345" alt="test image" />',
files: [
{
filename: 'test image',
contentType: 'image/jpeg',
cid: '12345',
content: base64_encode('test.jpg')
}
]
};
try {
sgMail.send(msg)
} catch(err) {
console.log(err)
}
If you need more information to solve this problem. Please tell me. Thank you.
You need to add disposition: inline to your attachment.
const msg = {
to: 'to address',
from: 'from address',
subject: 'subject',
html: '<strong>Some Text</strong><img src="cid:12345" alt="test image" />',
files: [
{
filename: 'test image',
contentType: 'image/jpeg',
cid: '12345',
content: base64_encode('test.jpg'),
disposition: 'inline'
}
]
};
I have code that send email with nodemailer in nodejs but I want to attach file to an email but I can't find way to do that I search on net but I could't find something useful.Is there any way that I can attach files to with that or any resource that can help me to attach file with nodemailer?
var nodemailer = require('nodemailer');
var events = require('events');
var check =1;
var events = new events.EventEmitter();
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "gmail",
auth: {
user: "example#gmail.com",
pass: "pass"
}
});
function inputmail(){
///////Email
const from = 'example<example#gmail.com>';
const to = 'example#yahoo.com';
const subject = 'example';
const text = 'example email';
const html = '<b>example email</b>';
var mailOption = {
from: from,
to: to,
subject: subject,
text: text,
html: html
}
return mailOption;
}
function send(){
smtpTransport.sendMail(inputmail(),function(err,success){
if(err){
events.emit('error', err);
}
if(success){
events.emit('success', success);
}
});
}
///////////////////////////////////
send();
events.on("error", function(err){
console.log("Mail not send");
if(check<10)
send();
check++;
});
events.on("success", function(success){
console.log("Mail send");
});
Include in the var mailOption the key attachments, as follow:
var mailOptions = {
...
attachments: [
{ // utf-8 string as an attachment
filename: 'text1.txt',
content: 'hello world!'
},
{ // binary buffer as an attachment
filename: 'text2.txt',
content: new Buffer('hello world!','utf-8')
},
{ // file on disk as an attachment
filename: 'text3.txt',
path: '/path/to/file.txt' // stream this file
},
{ // filename and content type is derived from path
path: '/path/to/file.txt'
},
{ // stream as an attachment
filename: 'text4.txt',
content: fs.createReadStream('file.txt')
},
{ // define custom content type for the attachment
filename: 'text.bin',
content: 'hello world!',
contentType: 'text/plain'
},
{ // use URL as an attachment
filename: 'license.txt',
path: 'https://raw.github.com/andris9/Nodemailer/master/LICENSE'
},
{ // encoded string as an attachment
filename: 'text1.txt',
content: 'aGVsbG8gd29ybGQh',
encoding: 'base64'
},
{ // data uri as an attachment
path: 'data:text/plain;base64,aGVsbG8gd29ybGQ='
}
]}
Choose the option that adjust to your needs.
Link:Nodemailer Repository GitHub
Good Luck!!
Your code is almost right, just need to add, "attachments" property for attaching the files in your mail,
YOUR mailOption:
var mailOption = {
from: from,
to: to,
subject: subject,
text: text,
html: html
}
Just add attachments like
var mailOption = {
from: from,
to: to,
subject: subject,
text: text,
html: html,
attachments: [{
filename: change with filename,
path: change with file path
}]
}
attachments also provide some other way to attach file for more information check nodemailer community's documentation HERE
If you are passing options object in mail composer constructor and attachment is on http server then it should look like:
const options = {
attachments = [
{ // use URL as an attachment
filename: 'xxx.jpg',
path: 'http:something.com/xxx.jpg'
}
]
}
var express = require('express');
var router = express(),
multer = require('multer'),
upload = multer(),
fs = require('fs'),
path = require('path');
nodemailer = require('nodemailer'),
directory = path.dirname("");
var parent = path.resolve(directory, '..');
// your path to store the files
var uploaddir = parent + (path.sep) + 'emailprj' + (path.sep) + 'public' + (path.sep) + 'images' + (path.sep);
/* GET home page. */
router.get('/', function(req, res) {
res.render('index.ejs', {
title: 'Express'
});
});
router.post('/sendemail', upload.any(), function(req, res) {
var file = req.files;
console.log(file[0].originalname)
fs.writeFile(uploaddir + file[0].originalname, file[0].buffer, function(err) {
//console.log("filewrited")
//console.log(err)
})
var filepath = path.join(uploaddir, file[0].originalname);
console.log(filepath)
//return false;
nodemailer.mail({
from: "yourgmail.com",
to: req.body.emailId, // list of receivers
subject: req.body.subject + " ✔", // Subject line
html: "<b>" + req.body.description + "</b>", // html body
attachments: [{
filename: file[0].originalname,
streamSource: fs.createReadStream(filepath)
}]
});
res.send("Email has been sent successfully");
})
module.exports = router;
attachments: [
{
filename: "inovices_1.pdf", // the file name
path: "https://*************************/invoice/10_9_RMKUns.pdf",// link your file
contentType: "application/pdf", //type of file
},
{
filename: "inovices_2.pdf",
path: "https://**************************/invoice/10_9_RMKUns.pdf",
contentType: "application/pdf",
},
];
var nodemailer = require("nodemailer");
var all_transporter = nodemailer.createTransport({
host: process.env.MAIL_SERVICE,
port: 587,
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASS,
},
maxConnections: 3,
pool: true,
});
exports.send_email = function (email, subject, html, extra_cc = [], attachments = []) {
return new Promise(async (resolve, reject) => {
var mailOptions = {
from: process.env.MAIL_FROM_ADDRESS,
to: email,
subject: subject,
html: html,
cc: [],
};
mailOptions["cc"] = mailOptions["cc"].concat(extra_cc);
if (attachments.length > 0) mailOptions["attachments"] = attachments;
all_transporter.sendMail(mailOptions, function (error, info) {
// console.log(error);
// console.log(info);
if (error) {
resolve({ failed: true, err: error });
} else {
resolve({ failed: false, data: info.response });
}
});
});
};
The alternative solution is to host your images online using a CDN and link to the online image source in your HTML, eg. <img src="list_image_url_here">.
(I had problems with nodemailer's image embedding using nodemailer version 2.6.0, which is why I figured out this workaround.)
An added benefit of this solution is that you're sending no attachments to nodemailer, so the sending process is more streamlined.
var mailer = require('nodemailer');
mailer.SMTP = {
host: 'host.com',
port:587,
use_authentication: true,
user: 'you#example.com',
pass: 'xxxxxx'
};
Then read a file and send an email :
fs.readFile("./attachment.txt", function (err, data) {
mailer.send_mail({
sender: 'sender#sender.com',
to: 'dest#dest.com',
subject: 'Attachment!',
body: 'mail content...',
attachments: [{'filename': 'attachment.txt', 'content': data}]
}), function(err, success) {
if (err) {
// Handle error
}
}
});
Just look at here. Nodemailer > Message configuration > Attachments
The code snippet is below (pdfkit gets the stream):
// in async func
pdf.end();
const stream = pdf;
const attachments = [{ filename: 'fromFile.pdf', path: './output.pdf',
contentType: 'application/pdf' }, { filename: 'fromStream.pdf', content: stream, contentType: 'application/pdf' }];
await sendMail('"Sender" <sender#test.com>', 'reciver#test.com', 'Test Send Files', '<h1>Hello</h1>', attachments);
Stream uses content not streamSource This bothered me before, share with everyone :)
Reference = https://nodemailer.com/message/attachments/
var mailOption = {
from: from,
to: to,
subject: subject,
text: text,
html: html,
attachments: [
{
filename: filename,
path: filePath
},
]
}