Rails 和 Tailwind CSS 实现 HTML 邮件:完整指南
进入用户的邮箱是一种特权。作为 PlanetScale,我们非常注重细节,花费了大量时间来确保邮件的质量。
我们最近推出了每周数据库报告邮件。这些邮件会定期发送,帮助用户轻松查看数据库性能、活动情况及可以采取的下一步行动。
本文将介绍我们如何使用 Ruby on Rails 和 Tailwind CSS 构建每周数据库报告邮件的 HTML 邮件,并分享解决过程中遇到的挑战。
注意事项
本文并非完整的操作教程,而是一份参考指南,适合探索如何在你的应用程序中使用 Rails 和 Tailwind 构建 HTML 邮件的开发者。
设置 Rails 应用
如果你希望轻松跟随本文的内容,请确保你已经搭建好一个 Rails 应用,并将其设置为支持 PostCSS。我们建议使用 Rails 7+,同时安装 cssbundling-rails。
创建新的 Rails 应用:
rails new myapp --css postcss
更新现有 Rails 应用
如果你已经有一个 Rails 应用,但尚未配置 PostCSS,可以按照以下步骤完成设置。如果你刚刚创建了新的应用,则可以跳过此步骤。
添加 cssbundling-rails
:
./bin/bundle add cssbundling-rails
执行以下命令以生成一个基础设置:
./bin/rails css:install:postcss
如果系统提示覆盖现有文件,而你已有 postcss.config.js
文件,可以选择“不覆盖”(输入 n
)。
另外,如果在 app/assets/stylesheets/
目录下已有 application.css
文件,可以通过以下命令还原这些文件:
git restore --staged app/assets/stylesheets/application.css git checkout app/assets/stylesheets/application.css
删除生成的 application.postcss.css
文件:
rm app/assets/stylesheets/application.postcss.css
如果目录中已有 application.postcss.css
文件,选择“不覆盖”(输入 n
)。设置完成后,我们就可以配置 PostCSS。
配置用于邮件的 PostCSS
我们需要单独设置两个 CSS 文件:一个用于 Web 应用,另一个用于邮件。为什么这样做?因为邮件客户端对 CSS 的支持非常有限,与 Web 的 CSS 不完全相同。我们现在来创建邮件专用 CSS 文件:
创建邮件 CSS 文件:
touch app/assets/stylesheets/mailer.postcss.css
每个 CSS 文件将使用不同的 Tailwind 配置,以优化其使用场景。通过 PostCSS CLI,可以轻松生成这些分离的文件。
修改 package.json
:
{ "scripts": { "build:css": "postcss ./app/assets/stylesheets/{application,mailer}.postcss.css --base ./app/assets/stylesheets --dir ./app/assets/builds" } }
接下来,编译 CSS 文件:
yarn build:css
验证生成的 CSS 文件是否存在:
ls app/assets/stylesheets/
生成的文件实际上只是经过 PostCSS 处理后的纯 CSS 文件。可以通过以下命令删除 .postcss
扩展名:
mv app/assets/stylesheets/application{.postcss,}.css mv app/assets/stylesheets/mailer{.postcss,}.css
重新编译 CSS:
yarn build:css
验证更新结果:
ls app/assets/builds/
创建邮件专用的样式表
设置 Tailwind 并配置 PostCSS,这将允许我们分别优化针对 Web 和邮件的输出。
安装 Tailwind CSS
yarn add tailwindcss postcss autoprefixer postcss-import --dev
初始化 Tailwind CSS:
yarn tailwindcss init
更新 PostCSS 配置文件:
// postcss.config.js module.exports = (api) => { if (/mailer/.test(api.file.basename)) { return { plugins: { 'postcss-import': {}, 'postcss-custom-properties': { preserve: false }, 'tailwindcss/nesting': {}, tailwindcss: { config: './tailwind.config.mailer.js' } } } } return { plugins: { 'postcss-import': {}, 'tailwindcss/nesting': {}, tailwindcss: {}, autoprefixer: {} } } }
配置邮件专用的 Tailwind 文件
编辑 tailwind.config.mailer.js
文件:
module.exports = { content: ['app/helpers/mailer_helper.rb', 'app/views/*_mailer/*.html.erb', 'app/views/layouts/mailer.html.erb'], future: { disableColorOpacityUtilitiesByDefault: true }, theme: { extend: { borderRadius: { none: '0', xs: '2px', sm: '4px', DEFAULT: '6px', md: '8px', lg: '10px', full: '9999px' }, fontSize: { xs: '10px', sm: '12px', base: '14px', lg: '16px', xl: '18px', '2xl': '22px', '3xl': '24px', '4xl': '28px', '5xl': '32px' }, spacing: { 0.5: '4px', 1: '8px', 1.5: '12px', 2: '16px', 2.5: '20px', 3: '24px', 4: '32px', 4.5: '36px', 5: '40px', 6: '48px', 7: '56px', 8: '64px', 9: '72px', 10: '80px' } } } }
内联 CSS 样式的重要性
邮件客户端对样式文件的支持普遍较差。最简单的解决方法是将样式内联到 HTML 中,但这种方式容易出错且难以维护,因为你无法使用 CSS 类或在 HTML 中重用样式。
为了解决这一问题,我们使用了一个叫 roadie 的库,它能够自动将外部样式转换为内联样式,并且与 Tailwind CSS 兼容。
安装 Roadie Rails
./bin/bundle add roadie-rails
配置 Roadie Rails
编辑 app/mailers/application_mailer.rb
文件,将以下内容添加进去:
class ApplicationMailer < ActionMailer::Base include Roadie::Rails::Automatic default from: "from@example.com" layout "mailer" end
设置邮件布局
邮件布局中的主要容器是一个包裹内容的外层框架。通常,在邮件中这是一个约 600px 宽的居中栏,能够在更小的屏幕上自动缩小并居中显示。
以下是一个布局示例:
<!DOCTYPE html> <html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title><%= message.subject %> | PlanetScale</title> <%= stylesheet_link_tag "mailer" %> </head> <body> <div role="article" aria-roledescription="email" aria-label="<%= message.subject %>" lang="en"> <table border="0" cellpadding="0" cellspacing="0" class="font-sans" width="100%"> <tr> <td height="32"></td> </tr> <tr> <td align="center"> <table border="0" cellpadding="0" cellspacing="0" class="w-full max-w-[684px] px-0 sm:w-[684px] sm-px-2" width="100%"> <tr> <td> <%= yield %> </td> </tr> </table> </td> </tr> <tr> <td height="32"></td> </tr> </table> </div> </body> </html>
支持深色模式(Dark Mode)
许多用户更喜欢深色模式,因此支持它非常重要。Tailwind CSS 让我们轻松实现了这一功能。
在 <head>
部分添加以下元标签:
<meta name="color-scheme" content="light dark"> <meta name="supported-color-schemes" content="light dark only">
然后在 CSS 文件中定义样式:
/* app/assets/stylesheets/mailer.css */ @import 'tailwindcss/base'; @import 'tailwindcss/components'; @import 'tailwindcss/utilities'; :root { color-scheme: light dark; supported-color-schemes: light dark; } @media (prefers-color-scheme: dark) { body { background-color: #111 !important; color: #fafafa !important; } a { color: #47b7f8 !important; } }
添加邮件预览文字(Preheader)
预览文字是一种鼓励用户打开邮件的好方法。它通常是邮件主题旁边的文本内容。以下是设置预览文字的方法:
在 /app/views/database_mailer/database_weekly_report.html.erb
文件中添加:
<% content_for :preheader do %> <%= @report.period_start_label(full: false) %> – <%= @report.period_end_label(full: false) %> Here’s a look at the performance of your <%= @database.display_name %> database. <% end %>
然后在布局文件 /app/views/layouts/mailer.html.erb
中:
<!DOCTYPE html> <html> <body> <% if content_for?(:preheader) %> <div class="hidden"> <%= yield :preheader %> </div> <% end %> </body> </html>
禁止 Apple 自动链接
在 iPhone 或 iPad 中查看邮件时,电话号码、地址、日期甚至一些特定词(例如“今晚”)经常被自动转化为蓝色超链接。这些链接会触发应用事件,例如拨号或创建日历事件。这在某些场景中可能很方便,但对于许多设计和品牌来说,这恰恰是个干扰。
以下是关闭自动链接的方法:
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no, url=no"> <meta name="x-apple-disable-message-reformatting">
解决 Gmail 内容截断问题
Gmail 在邮件内容超过 102KB 时,会截断并用“查看完整内容”链接显示剩余部分。这对用户体验而言是不理想的。
剔除不必要的内容
建议删除所有不必要的内容。例如,我们限制显示的慢查询记录数量为 10 条:
<% @report.slow_queries.first(10).each do |query| %> <tr> <td class="font-mono text-sm text-primary"> <%= truncate(query.sql, length: 200) %> </td> </tr>
此外,可以使用链接转向完整内容:
<% @report.slow_queries.first(10).each do |query| %> <tr> <td class="font-mono text-sm text-primary"> <%= truncate(query.sql, length: 200) %> </td> <td align="right"> <%= link_to "View full query", query %> </td> </tr>
减少文件大小
即便裁剪内容后,邮件有时仍会被截断。我们可以通过优化 Tailwind 的导入来进一步减少文件大小:
/* 替换部分导入 */ @import 'tailwindcss/utilities'; @import 'mailer/base'; @import 'mailer/theme';
我们删除了 Tailwind 的预检样式和组件工具,靠自定义样式减少总体文件大小:
html { line-height: 1.5; } body { line-height: inherit; margin: 0; } img { border-style: none; display: block; vertical-align: middle; max-width: 100%; height: auto; }
测试结果显示,我们的邮件大小从 80KB 减少到 45KB,成功解决 Gmail 内容截断问题。
Gmail 桌面样式优化
尽管我们设计了响应式样式,但在 Gmail 桌面版中,邮件的移动端样式始终被应用。这是因为 Gmail 不支持某些 CSS 转义字符。
解决方法:定义辅助工具类
由于 Gmail 不支持特殊符号的转义输出,建议定义自定义工具类来处理样式问题:
@media (min-width: 640px) { .sm-block { display: block !important; } .sm-hidden { display: none !important; } .sm-inline { display: inline !important; } }
然后更新代码:
<span class="hidden sm-inline">显示在桌面端</span>
测试邮件内容
邮件预览
Rails 提供一个简单的方式在浏览器中预览邮件样式。在 test/mailers/previews/database_mailer_preview.rb
文件中创建邮件预览类:
class DatabaseMailerPreview < ActionMailer::Preview def database_weekly_report DatabaseMailer.with( database: database, recipient: user, report: report, subscription: subscription, ) end private def database Database.first! end def recipient User.first! end def report DatabaseReport.new( database: database, period_start: Time.current.beginning_of_week, period_end: Time.current.end_of_week, ) end def subscription Subscription.new( database: database, user: user, ) end end
预览 URL 为 http://localhost:3000/rails/mailers/database_mailer/database_weekly_report
。
发送测试邮件
为了在真实邮件客户端中测试样式和功能,可以创建一个 Rake 任务,用于发送测试邮件,代码如下:
namespace :dev do namespace :mailer do task :database_weekly_report, [:email] => :environment do |_t, args| raise ArgumentError, "Rails environment is not development" unless Rails.env.development? raise ArgumentError, "Email argument is missing" unless args[:email] mailer = DatabaseMailerPreview.new.database_weekly_report mailer.to = args[:email] mailer.deliver end end end
通过以下命令发送测试邮件:
bin/rails dev:mailer:database_weekly_report[info@planetscale.com]
总结
尽管构建 HTML 邮件较为复杂,但 Ruby on Rails 和 Tailwind CSS 让这个过程变得更为顺畅。它们不仅加快了开发过程,还简化了测试工作。如果你对实现细节有任何疑问,请随时联系!
关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台
除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接