画布与拖放
一个带有选择、拖拽目标、下放指示、调整大小和组件工具栏的 iframe 画布——那个需要几个月才能完善、没人会买你产品的交互层。
你的用户通过可视化方式构建邮件。你的应用程序控制着体验。
这是本页上运行的真实 GrapesJS 编辑器——不是视频,也不是截图。从右侧拖入一个块,选中任意元素即可重新设置样式,切换到手机宽度,然后把生成的标记读出来。页眉和页脚是锁定的,与下面章节讲解的模式完全一致。
你能做的事
拖放邮件构建器是一种可视化编辑器,允许用户用可重复使用的组件创建邮件布局,而无需手动编写HTML表格和针对邮件的CSS。
区别在于谁必须知道规则。没有构建器,写邮件的人需要知道布局是嵌套表格完成的,大部分样式必须是内联的,且一个客户端的边距会压缩设计。有了构建器,规则只需你编码一次,分成块和组件,其他人只需整理。
没有视觉构建器
有人手写表格标记,然后手做检查。每封新邮件都是从上一封的副本开始的。
<table role="presentation" cellpadding="0" cellspacing="0" width="600">
<tr>
<td style="padding:32px;font-family:Arial,sans-serif">
<h1 style="margin:0 0 12px;font-size:26px">欢迎</h1>
<p style="margin:0;font-size:15px;line-height:1.6">您的内容......</p>
</td>
</tr>
</table>使用拖放式构建器
有人会安排块。表格标记是从你定义并审查过一次的组件生成的。
构建器不是为了让邮件变得简单。它负责让别人做出难的决定——你一次性做出的,在组件层面。
网页运行在一个你大致可以理解的浏览器中。邮件运行在收件人打开的客户端中,而该客户端可能会重写你的标记、去除样式,或者用完全不同的引擎排版。因此,电子邮件构建器必须限制用户能产出的内容,而不仅仅是让生产过程愉快。
你的邮件必须存活的地方
Gmail
网页版、安卓版和iOS版应用的行为各不相同,网页客户端会在渲染前处理你的样式。
Outlook
桌面、网页和较新的Windows客户端实际上是不同的渲染器。Windows上的桌面构建历来是最严格的目标。
Apple Mail
最宽松的常见客户端,这也让它成为一个糟糕的代理:一封看起来就在这里的邮件,可能在其他地方出错。
Yahoo Mail
另一个有自己样式和标记净化规则的网页邮件客户端。
移动客户端
窄视口、激进的文本缩放,以及根据应用和操作系统版本不同的暗黑模式处理。
其他一切
企业网关、区域服务提供商以及那些从未出现在典型测试矩阵中的老旧客户端。
这对构建器提出了什么要求
布局是表格,不是Flexbox或网格
你的列、间隔和分隔符必须是表格组件。用户绝不应该能将裸 div 直接放入画布。
CSS 支持不稳定且不稳定
将Style Manager限制在你实际测试过的属性上,而不是暴露浏览器的全部属性。
样式在内排最安全
要么用导出时内嵌的预设作者,要么在邮件离开后台前,在自己的流程里运行内嵌工具。
媒体提问并非普遍被尊重
设计时,单列备份已经是可接受的,并且将响应式规则视为改进而非必需。
图片通常默认被屏蔽
要求每个图片组件都加备用文本,并且绝不要让某个块依赖图片才能可读。
暗色模式可能会重新给你的邮件颜色
有些客户端会自动反转或调整颜色。避免设计依赖于特定背景保持该颜色的方案。
网页字体经常无法加载
在每个文本组件上都发布一个真正的备用栈,并且用备援而不是预期的面孔来检查邮件。
脚本无法运行,交互性有限
任何动态的东西都应该被链接支持。一个向用户提供交互式模块的构建器,实际上是在给他们提供无法正常工作的东西。
商业邮件带有法律要求
发送者身份和取消订阅机制是义务,而非设计选择。将它们锁定在模板中,而不是信任清单。
你不是在构建一个能产出漂亮HTML的编辑器。你是在打造一个无法产生危险HTML的编辑器。
客户端行为会随着发布和渲染模式变化,因此本页没有针对每个客户端的支持矩阵。验证你自己用户实际使用的客户端和功能。最后评测时间为2026-09-03。
GrapesJS 是一个开源(BSD-3-Clause)网页构建框架,目前是 0.23.6,GitHub 上大约有 26k+ 的星级。它给你编辑器中那些构建成本高且区分乏味的部分,同时为真正属于你产品的部分避开了。
一个带有选择、拖拽目标、下放指示、调整大小和组件工具栏的 iframe 画布——那个需要几个月才能完善、没人会买你产品的交互层。
定义一个邮件安全的组件一次,然后将其暴露为用户拉入的阻挡。组件有自己的规则:接受什么、可编辑什么、样式化什么。
一个样式面板,你可以限制在邮箱实际支持的属性上,还有一个 traits 面板,用于设置非 CSS 的设置——链接目标、替代文本、合并字段。
一个用于嵌套表的结构树,这些表难以通过点击选择,还有一个你可以指向自己媒体库的资产管理器。
整个编辑器的状态序列化成 project JSON。把 Storage Manager 指向你的 API,编辑器就不再在意数据在哪里了。
每个编辑器操作都是一个命名命令,你可以调用、覆盖或添加——这就是预设、导出器和GJS.Market上的100+插件如何扩展它而无需分支的方式。
GrapesJS 提供编辑层。你的应用程序提供电子邮件产品。
你的产品:账户、租户、账单,编辑者所挂载的路线。
编辑器的外壳:模板选择器、保存状态、发送按钮、审批。
视觉编辑引擎。它只知道组件和画布,却对你的用户一无所知。
你配置的编辑器子系统:哪些块存在,哪些块能接受,哪些可以样式,哪些可以编辑。
序列化编辑器状态。这是你存储的内容,以便邮件以后可以重新打开。
你的API:权限、版本管理、合并标签解析、验证、活动记录。
你实际发送的标记。按需从存储的项目生成。
邮件投递服务商并报告邮件发生情况。
收件箱,以及负责渲染它的客户端。
GrapesJS 从不与你的数据库或邮件提供商通信。它会给你一份文档;之后的一切都是你的架构。
三位所有者,没有重叠。本页主题中最常见的架构错误是期望编辑在右侧栏做些什么。
右侧两列并不是 GrapesJS 的缺失——这些事情从来就不是编辑器的职责。从第一个迭代开始就把它们当作应用层的工作,集成才能保持简单。
有三个工件来自同一个画布,它们不能互换。一个是你保留的项目,另一个是你从中生成的交付格式。
电子邮件的可编辑表示——组件、样式、资源和页面,完全符合编辑者持有的状态。
最适合
你是怎么得到的
editor.getProjectData()这是要存储的。只存储渲染的HTML意味着下一次编辑是从解析标记开始,而不是从用户构建的文档开始。
基于表格的标记,你交给发送服务商,样式内嵌,以便更多客户端保留。
最适合
你是怎么得到的
editor.runCommand('gjs-get-inlined-html')内联命令来自新闻通讯预设,而不是 GrapesJS 核心。没有它,你会得到画布标记和样式表,这不是你想发送的。
一种更高级的电子邮件标记语言,可编译为响应式表 HTML。
最适合
你是怎么得到的
editor.runCommand('mjml-code')MJML 是一个独立的生态系统:编辑器插件渲染 MJML 组件,编译器将它们转换成 HTML。这两个都是第三方包,你会添加。
JSON 是项目。HTML 和 MJML 是交付。存储第一个,生成其他。
从画布到收件箱
不要给用户一张空白画布和一个 div。先发布一小组组件,这些组件已经编码了表格标记、内联样式和备用,然后让用户自行排列。这十个组件涵盖了大部分营销和生命周期邮件的实际需求。
标志、品牌条、前置标题文字。通常会被锁定,所以每封邮件都保持相同的身份。
标题、辅助行和一个动作。大小使消息在不加载图像的情况下依然存在。
一个带有真实字体备用堆栈和行高的段落块,能在手机宽度下保持。
固定宽度、明确尺寸和必填替代文本,所以被屏蔽的图片仍然能保持邮件可读。
基于表格的按钮而非样式锚点——区别在更严格的客户端中可见。
一个表格行,在窄视口下自动堆叠,堆叠顺序由你预先决定。
图片、名称、价格和链接,由后台填充的字段驱动,而不是复制粘贴。
一排固定的图标和网址,可以通过设置编辑,而不是标记。
用表格边框而不是 <hr> 元素画出的分隔线——多个邮件客户端会重新渲染 <hr>。
发送者身份、地址和退订链接。通常是锁定的,因为这些是义务。
让用户在不要求他们理解 HTML 邮件的情况下进行视觉设计。
组件是定义;块是用户将组件放到画布上的方式。块库是你控制人们能构建什么的最有力杠杆——也是最容易因慷慨而出错的杠杆。
用户重复的循环
所有可用元素,每种风格都可以编辑,对结构没有意见。
一份你设计、测试过并可在中心更换的区块简短列表。
三个层级,而这正是邮件构建器难以成长的原因。组件就是物品,块是添加方式,模板是完成的起点。
模板
用户可以从一整封邮件开始——通讯、收据、入职步骤。作为项目JSON存储,使用时克隆。
块
模板的可拖动单元包括:hero、条目行、CTA条带、页脚。
组件
这些可编辑的原语放在一个区块里,拥有自己的traits和规则——一张知道价格的产品卡。
先构建组件,然后是暴露组件的模块,最后是排列组件的模板。从模板层面开始的团队最终会得到几十个几乎相同的设计,且无法更改。
扩展版通讯模板
通讯模板
每个子块是一个模块;每个模块由组件组成。只需更改一次文章模块,每个基于该模板构建的通讯下一次打开时都会接收该模块。
GrapesJS 中的锁定不是一个模式或计划层级——它是组件定义上的一组选项。锁定区域仍然会渲染、导出,并且在编辑器中拒绝拖拽、删除或重新样式。
公司页眉
锁定每封邮件都要出现,每封邮件都一样。没人需要移动它。
可编辑内容
可编辑发送者实际上是来写的文字和图片。
行动号召
可编辑可编辑标签和链接,还有一份简短的颜色列表——不是下面的标记。
法律页脚
锁定发送者身份和退订链接。这是义务,不是设计决策。
产生这种变化的选项
removable: false, draggable: falseeditable: truestylable: ['background-color', 'color']removable: false, copyable: false这能给你带来什么
这些选项控制编辑器UI。它们不是授权。直接发布到你的存档端点的修改项目仅受服务器验证的约束——所以每次都要验证后端的结构、所需区域和允许字段。
个性化邮件有两个独立的问题:让用户在不知道语法的情况下放置占位符,以及在发送时用真实数据解决占位符。编辑器解决了第一个问题。只有你的应用程序能解决第二个问题。
模板中的标签合并
{{first_name}}{{company_name}}{{order.total}}{{unsubscribe_url}}对编辑来说,这些只是普通文本。它们被完全按原文存储,保存、重新打开和导出时都未受影响。
用户如何插入
在你的文本组件中,将可用字段作为特征暴露——比如“名字”、“公司”、“订单总额”的下拉菜单——然后自己把令牌写入内容中。用户选择一个字段;他们永远不会学习语法,也不能创造渲染器不知道的标签。
动态块
块可以作为尚未存在内容的占位符。用户输入产品卡并配置显示哪些产品;这些值在邮件渲染时到达。
GrapesJS 提供编辑体验。你的后台在邮件渲染或发送时解析动态数据和合并标签。
两种宽度几乎涵盖了设计审查的全部内容:邮件写作的宽度和手机宽度。两者在编辑器中只需切换设备即可,且都不等同于测试。
真正发现问题的工作流程
编辑器内预览是浏览器渲染画布标记。邮件客户端通过自身引擎渲染该标记的转换版本,两者可能有所不同。预览用于设计审查;种子列表或渲染服务用于兼容性。
大多数邮件灾难并不是渲染bug。它们是链接断裂、合并标签未填或取消订阅缺失。这三种情况在服务器上发现成本低,收件箱发现成本高。
在模板还没能退出草稿之前就跑。
自动化成本低,且是最常见的单次故障。
不可协商,所以要用代码而非清单来执行。
Storage Manager 是一个接口,不是数据库。在你自己的 API 上实现它,编辑器会通过你控制的端点加载、自动保存和恢复——这正是草稿、版本和批准成为可能的节点。
后端定义的生命周期
// The editor hands you project JSON; your backend decides
// what a draft, a version and an approved template mean.
editor.Storage.add('email-api', {
async load({ templateId }) {
const res = await fetch(`/api/email-templates/${templateId}`);
return res.json(); // -> project JSON
},
async store(data, { templateId }) {
await fetch(`/api/email-templates/${templateId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
// Authorization is enforced server-side. Never trust this call.
body: JSON.stringify({ project: data }),
});
},
});自动保存是根据变更次数而非定时器限制的,因此一次编辑突发仍需一次请求。保持版本为JSON项目的不可变副本——恢复修订后只需加载,错误编辑不再是事件。
这个架构没有要求你更改发送邮件的方式。编辑器生成文档;你的后端渲染文档并交给你已经付费的供应商。
GrapesJS
负责项目,并应要求进行加注。对接收者一无所知。
HTML / MJML
按需从存储的项目生成,样式内嵌或编译MJML。
你的后台
解析合并标签,验证输出,记录活动,调用提供者。
你的邮件服务商
负责送信、报告退信、投诉、打开邮件并点击回来。
后端发布的示例
按字母顺序列出,作为上一跳的示例。任何拥有HTTP API或SMTP端点的提供者都符合相同形状,且互换不会触及编辑器。
GrapesJS 是编辑器,不是你的邮件投递服务。
GrapesJS 和 GJS.Market 均未与上述任何供应商集成,也不意味着有合作关系。交付能力、认证和抑制处理仍由您的服务提供商和应用负责。
// Server side. GrapesJS is not in this file — and that is the point.
const template = await db.emailTemplates.find(templateId);
// 1. Your application resolves merge tags. The editor never does.
const html = renderMergeTags(template.html, {
first_name: user.firstName,
unsubscribe_url: unsubscribeUrlFor(user),
});
// 2. Your ESP delivers it. Swap the client, keep the editor.
await esp.send({ to: user.email, subject: template.subject, html });同一个编辑层,但被打包成八种不同的方式。它们之间的区别在于谁编辑、允许修改的内容以及输出的去向。
让客户在你的产品内设计生命周期和活动邮件,基于你每个计划控制的模板和模块。
SaaS 构建架构给市场团队一个视觉编辑,采用定期刊格式,并有一个文章块,保持每期内容一致。
通讯插件撰写那些位于活动和工作流程中的邮件,与它们指向的着陆页共享块。
着陆页构建器收据和通知模板严格控制——大多锁定,中间有一个小可编辑的部分。
模板系统让内容团队重复使用他们已经用来编写网页内容的模块,这些模块与内容模型的其他部分一起存储。
无头CMS编辑一个编辑器,为每个客户准备一套品牌块,模板在两次评审之间不会被改得面目全非。
白标构建器为内部团队提供一个受控编辑器,而不是共享的HTML文件和请求队列。
开发者无需代码让编辑器看起来和行为都像你产品的一部分,从面板、图标到语言都一样。
白标化编辑器这不是判断,而是范围检查。每一行都是邮件生成器需要的。左列是你自己拥有的工作;右列是GrapesJS在你写组件前给你的。
| 能力 | 从零开始 | 使用 GrapesJS |
|---|---|---|
| 视觉画布 | 自己实现 | 可得 |
| 拖放 | 自己实现 | 可得 |
| 组件模型 | 自己实现 | 可得 |
| 区块库 | 自己实现 | 可扩展性 |
| 样式编辑 | 自己实现 | 可得 |
| 层树 | 自己实现 | 可得 |
| 撤销/重做 | 自己实现 | 可得 |
| 资产管理 | 自己实现 | 可得 |
| 存储集成 | 自己实现 | 可配置 |
| 自定义组件 | 自己实现 | 支持 |
| 插件架构 | 自己实现 | 支持 |
“可用”意味着该能力随核心一同发布,只需配置,而不必从零构建。但这并不意味着不需要工作:任何认真的邮件构建器都要定义自己的组件、限制自己的样式,并编写自己的存储适配器。已于 2026-09-03 针对 grapesjs 0.23.6 验证。
打造你的电子邮件产品,而不是另一个编辑引擎。
GJS.Market目录中的真实商品,按所属组装阶段分组。名称、价格和图片直接来自市场,所以你看到的就是今天实际出售的商品。
本页部分功能背后没有插件,本节也不会发明插件:目录中没有预览或垃圾邮件检查产品、CSS内联产品、合并标签产品以及现成的邮件模板产品。这些在这里被描述为可实施的模式,或是我们团队可以与你合作的工作。
四个构建,仅从现有的商品列表中组装而成。从你要发货的那一行开始,等它有位置时再添加下一层。
第一个内部编辑器:拖动块,保存模板,导出HTML。
MJML 创作、设计的块集、模板以及每个组件的代码逃逸出口。
面向客户:MJML 输出、模板记录、远程存储和限速 autosave。
参见SaaS架构营销团队的编辑器:块、模板和托管素材,这些素材比草稿更久。
价格来自构建时的实时目录。免费列表会被标记;付费列表直接链接到他们的产品页面。
作品的形状,以及正确的顺序。每个步骤都链接到正确覆盖的指南——本页是地图,不是教程。
先把GrapesJS挂载在容器上,设置两个设备对邮件的需求,然后先关闭默认的本地存储。
GrapesJS 设置指南 →写出基于表格的邮件组件,限制样式,并以块形式展示每个组件。
电子邮件组件深入解析 →给用户一个起点。将模板存储为项目JSON,使用时克隆模板,而不是编辑原始模板。
模板系统 →针对你的API实现存储适配器,这样草稿、autosave及其版本由你自己定义。
存储插件 →发送时生成标记,服务器端解析合并标签,然后把结果交给你的提供商。
寻求搭建帮助 →import grapesjs from 'grapesjs';
import newsletter from 'grapesjs-preset-newsletter';
const editor = grapesjs.init({
container: '#email-editor',
height: '100%',
// Email is authored at a fixed width; give users one extra viewport
// to check, not a full responsive breakpoint set.
deviceManager: {
devices: [
{ id: 'desktop', name: 'Desktop', width: '' },
{ id: 'mobile', name: 'Mobile', width: '375px' },
],
},
// Curated blocks only: the preset's table sections, plus your own.
plugins: [
(ed) => newsletter(ed, { inlineCss: true, showBlocksOnLoad: true }),
],
// Point the editor at your API rather than the browser's localStorage.
storageManager: {
type: 'remote',
autosave: true,
stepsBeforeSave: 10,
},
});// An email-safe button: users edit the label and the link,
// never the table markup that makes it render in Outlook.
editor.DomComponents.addType('email-button', {
isComponent: (el) => el.dataset?.type === 'email-button',
model: {
defaults: {
draggable: '[data-gjs-type="cell"], td',
// Users may recolour it; they may not restyle it into a div.
stylable: ['background-color', 'color', 'border-radius'],
traits: [
{ name: 'href', label: 'Link' },
{ name: 'label', label: 'Button text' },
],
components: `
<table role="presentation" cellpadding="0" cellspacing="0">
<tr><td><a href="#">Read the update</a></td></tr>
</table>`,
},
},
});两个采样都运行在grapesjs 0.23.6上。“grapesjs-preset-newsletter”和“grapesjs-mjml”是独立的BSD-3-Clause封装——核心不含邮件预设——所以安装与你上面选择的输出格式相符的格式即可。
什么区别于一个可用的演示和一个可以交给客户的邮件生成器?这里的所有内容都是你的工作,不是编辑器的。
用户能做什么、不能做什么。
用户制作的任何东西都不应该丢失。
每次都在服务器上验证。
那些不关设计的部分。
电子邮件构建器接受用户自创的标记并发送给第三方。这种组合比典型的CRUD功能更值得关注。
风险
锁定区域、受限样式和隐藏块都存在于浏览器中。精心制作的请求可以发布任何它喜欢的项目。
该怎么办
验证服务器上已保存的项目:有需要的区域、允许列表中的组件类型、在范围内的字段。
风险
代码嵌入组件是每个邮件构建器都会收到的功能请求,它是一个指向客户收件箱的注入面。
该怎么办
净化存储的标记,并在渲染时重新净化。限制代码组件的使用权限,并记录每次使用。
风险
编辑上传的邮件最终会被放在与邮件存续时间相同的公开网址上。
该怎么办
在服务器上验证类型和大小,重新编码图像,并从不携带会话 Cookie 的域名中提供资源。
风险
渲染和发送是昂贵且不可逆的操作。它们通常比编辑器路线保护得不那么严格。
该怎么办
按模板和收件人列表授权,限制速率发送,并在发送给完整受众前要求第二次检查。
风险
宽松模板渲染器会乐意插值发送方本不该看到的字段。
该怎么办
根据该模板的显式允许列表解析,渲染失败于未知标签,而不是发出该标签。
编辑器是你应用中一个重要的依赖。这些杠杆才是关键,按它们通常的收益顺序排列。
懒散地加载编辑器
只在编辑邮件的路由中导入,且只在浏览器中导入。编辑器的任何内容都不属于服务器渲染或主捆绑包。
懒加载可选插件
代码查看器、图像编辑器或 MJML 编译器可以在用户打开该面板时出现,而不是在初始值时。
保持区块图书馆简短
每个块在启动时都会解析标记,并在调色板中渲染一张卡片。策划的集合既快又安全。
为 autosave 加防抖
通过变更计数而非按键来限速,因此一次打字会生成一个请求,而不是三十个。
保持项目数据精简
通过URL引用资源。项目JSON中的Base64图片会让每次加载、保存和版本副本变得更重。
留意自定义组件
组件逻辑在每次更改时都运行,是导致画布在长邮件中显得迟缓的常见原因。
这里故意不引用任何数据:数字取决于你的块数、组件逻辑和用户硬件。在每次更改前后,在你自己的应用中测量编辑器路由。
既然架构已经清晰,取舍也就很容易说清楚了。托管构建器能更快地摆在客户面前;你自己拥有的构建器则是产品的一项功能,而不是产品的一个依赖。
一个由厂商操作的可嵌入编辑器,通过其API和UI集成。
你能得到什么
最快找到工作编辑的路线,路线图和定价由别人掌控。
与托管供应商进行比较这是一个开源编辑层,你可以配置、扩展并部署,作为你自己应用的一部分。
你能得到什么
前期工作更多,编辑会随着你的产品成长而非绕着产品成长。
开始构建托管平台之间差异很大,这也是为什么左侧栏写“取决于提供商”,而不是一概而论。请查看具体供应商关于数据位置、保留、定制限制以及离开模板后处理情况的条款。
GrapesJS 渲染成一个普通的 DOM 元素,因此整合它取决于哪个生命周期钩子调用 init,哪个调用 destroy。你的框架驱动你的应用;GrapesJS 驱动可视化邮件编辑层。
如果你更愿意让它正常运行而不是研究它,我们的团队基于GrapesJS构建了电子邮件编辑服务——包括本页中没有插件支持的部分。
为用户提供一种可视化的方式来创建邮件,而无需强迫开发团队从零开始构建邮件编辑器。
告诉我们编辑需要做什么,并制定一个整合的具体计划。
开始构建市场上的预设、块、模板、存储和资源插件。
探索电子邮件插件组件、模板、存储和发布,都交付到你的栈上。
咨询GrapesJS专家你的用户负责构建邮件。你的产品拥有整个体验。