如何在EJS模板中导入CSS样式并邮件发送,同时维持现有文件结构
解决Express+EJS+Nodemailer邮件样式内联与模板分离问题
邮件客户端几乎都不支持外部CSS文件引用,所以核心思路是把所有分离的CSS合并后内联到HTML中,同时完全保留你现有的文件结构,解决授权和样式失效的问题。
1. 编写CSS合并工具函数
你的样式分为三级(全局→组→模板自身),按优先级读取合并(自身样式覆盖组和全局样式),用Node.js的fs和path模块实现:
import fs from 'fs/promises'; import path from 'path'; // 合并指定模板的各级CSS async function getCombinedStyles(viewGroup: 'internal_view_group' | 'public_view_group', templateName: string): Promise<string> { const styles: string[] = []; const basePath = './views'; // 读取全局样式 try { const globalStyle = await fs.readFile(path.join(basePath, 'style.css'), 'utf8'); styles.push(globalStyle); } catch (err) { console.warn('全局style.css未找到,跳过'); } // 读取组级样式 try { const groupStyle = await fs.readFile(path.join(basePath, viewGroup, 'style.css'), 'utf8'); styles.push(groupStyle); } catch (err) { console.warn(`${viewGroup}组style.css未找到,跳过`); } // 读取模板自身样式(优先级最高) try { const templateStyle = await fs.readFile(path.join(basePath, viewGroup, templateName, 'style.css'), 'utf8'); styles.push(templateStyle); } catch (err) { console.warn(`${templateName}模板style.css未找到,跳过`); } // 合并所有样式,后添加的样式会覆盖前面的规则 return styles.join('\n'); }
2. 渲染EJS时注入内联样式
在Express路由中先合并对应模板的CSS,再将样式作为变量传给EJS,在模板内用<style>标签包裹实现内联:
Express路由示例
import express from 'express'; import { renderFile } from 'ejs'; import nodemailer from 'nodemailer'; import { getCombinedStyles } from './utils/css-combiner'; import path from 'path'; const router = express.Router(); // 发送邮件接口 router.post('/send-email', async (req, res) => { const { viewGroup, templateName, lang, recipientEmail } = req.body; // 1. 合并当前模板的所有层级样式 const combinedStyles = await getCombinedStyles(viewGroup, templateName); // 2. 渲染指定语言的EJS模板,传入合并后的样式变量 const emailHtml = await renderFile( path.join('./views', viewGroup, templateName, `${lang}.ejs`), { combinedStyles } ); // 3. 配置Nodemailer并发送邮件 const transporter = nodemailer.createTransport({ host: 'smtp.your-domain.com', port: 587, secure: false, auth: { user: 'your-account@your-domain.com', pass: 'your-auth-pass' } }); await transporter.sendMail({ from: 'your-account@your-domain.com', to: recipientEmail, subject: '带样式的测试邮件', html: emailHtml // 直接发送内联了样式的HTML内容 }); res.status(200).send('邮件发送成功'); });
EJS模板修改(以en-us.ejs为例)
在模板的<head>中注入合并后的样式:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>邮件标题</title> <!-- 内联合并后的所有样式 --> <style><%= combinedStyles %></style> </head> <body> <!-- 原有模板内容 --> <div class="template-container"> <h1>Hello, <%= username %></h1> <p>This is a styled email.</p> </div> </body> </html>
方案优势
- 完全保留现有文件结构:全局、组、模板三级样式仍分离存放,维护逻辑不变
- 解决授权问题:无需外部样式路由,所有样式内嵌在HTML中,邮件客户端直接读取
- 解决样式失效问题:内联样式是邮件客户端兼容的标准写法,适配绝大多数邮箱服务商
内容的提问来源于stack exchange,提问作者Nekit
相关产品推荐
相关产品推荐

