使用SendGrid向Gmail发送内嵌图片失败,Nodemailer+Zoho可正常实现
如何使用SendGrid向Gmail发送内嵌图片?
我正在按照SendGrid官方教程尝试发送带内嵌图片的邮件,但通过SendGrid发送后,Gmail无法加载图片:

我使用的SendGrid代码如下:
const sgMail = require('@sendgrid/mail'); sgMail.setApiKey(process.env.SENDGRID_API_KEY); const msg = { to: 'somemail@gmail.com', // 收件人邮箱 from: 'company@company.com', // 已验证的发件人 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); });
我还尝试过使用Base64字符串作为content值:
const buf = '_9j_4AAQSkZJRgABAQAASABIAAD_4QguRXhpZgAATU0AKgAAAAgADAEPAAIAAAAGAAAAngEQAAIAAAAJAAAApAESAAMAAAABAAEAAAEaAAUAAAABAAAArgEbAAUAAAABAAAAtgEoAAMA..... ... content: `data:image/png;base64,${buf}`,
但使用Nodemailer搭配Zoho邮箱发送时,内嵌图片可以在Gmail中正常显示,说明问题不在Gmail:

对应的Nodemailer代码:
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(); } catch (err) { console.error(err); }
解决方法
问题根源
- SendGrid Node.js SDK不支持
files参数,正确的内嵌附件参数是attachments content字段必须是纯Base64编码的文件内容,不能直接填写远程图片URL(SendGrid不会自动下载远程图片嵌入邮件)- 使用Base64时不能带
data:image/png;base64,前缀,否则会导致解析错误
修正后的代码
先通过工具下载远程图片并转换为Base64,再传入SendGrid的attachments参数:
const sgMail = require('@sendgrid/mail'); const fetch = require('node-fetch'); // 需要先安装:npm install node-fetch sgMail.setApiKey(process.env.SENDGRID_API_KEY); // 下载远程图片并转为Base64 const getBase64Image = async (imageUrl) => { const response = await fetch(imageUrl); const imageBuffer = await response.buffer(); return imageBuffer.toString('base64'); }; const sendEmailWithInlineImage = async () => { try { const imageBase64 = await getBase64Image('https://i.picsum.photos/id/1069/536/354.jpg?hmac=ywdE7hQ_NM4wnxJshRkXBsy-MHlGRylyqlb51WToAQA'); const msg = { to: 'somemail@gmail.com', from: 'company@company.com', subject: 'SendGrid 内嵌图片测试', html: `<strong>Some Text ${Date.now()}</strong><div style="border:10px solid blue;"><img src="cid:image123" alt="test image"/></div>`, attachments: [ { filename: 'image.jpg', contentType: 'image/jpeg', cid: 'image123', // 与html中的cid对应 content: imageBase64, // 纯Base64字符串 disposition: 'inline', }, ], }; const result = await sgMail.send(msg); console.log('邮件发送成功:', result); } catch (error) { console.error('邮件发送失败:', error); } }; sendEmailWithInlineImage();
本地图片的处理方式
如果是本地图片,直接读取文件转为Base64即可:
const fs = require('fs').promises; // 读取本地图片转为Base64 const getLocalImageBase64 = async (filePath) => { const imageBuffer = await fs.readFile(filePath); return imageBuffer.toString('base64'); };
内容的提问来源于stack exchange,提问作者Dashiell Rose Bark-Huss
相关产品推荐
相关产品推荐

