goodmail 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49fc7b9412bf9c59d6f4369f8a5ba26f7faaeffd982e98684dd294728254f1e9
4
- data.tar.gz: 858a30035cba78799ee8b133d3531e531e952658d9270f35a80ed1fd9cf982ea
3
+ metadata.gz: 6e5f7b80a8e5d2b54ce69e8737358ce7eeda55ff7e3ba0f666aa566f8c254e79
4
+ data.tar.gz: 31c65395f2f014a7a8d2d031e444541b4aa0a40812346d4e298ffda5bcd98bee
5
5
  SHA512:
6
- metadata.gz: 74d2b6dd4665aa63b5394d715d043193d03e64f0130913442f596db2663d546386bb06ea4fb6940966932877a09751b53972e95bbff619ec0d994fbcd29fc9af
7
- data.tar.gz: 8469b9ea99e5de6b53f6c31c4edfb53c4eaee37eb5bf557351a9576456f5907b4fc032f3cb916961c595063f2449584d63ec038c5bc903ab21c2a8ab495fe791
6
+ metadata.gz: '09ad22554e994be1d26b59c476b7977e81333342b3dd12f5f4664438858dfb4c46abae1b1fcc29821c10d56702bf102494d2a6b1ee91372f8aeea78fc08ecd25'
7
+ data.tar.gz: e4e92e864d2ede0eef9ff398cf4ce312b49486203dc79b86a5a9dc708d4a66c7687c7b777ebcd68e718823afbbdf7305f05ba74b7b263c57172993dc3305a783
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.4.1] - 2026-10-24
2
+
3
+ ### Fixed
4
+
5
+ - **The layout escapes the subject, the preheader and the unsubscribe URL.** The default layout wrote the subject into `<title>`, the hidden preheader and `<meta itemprop="name" content="…">`, and the unsubscribe URL into `href="…"`, without HTML escaping. A subject that holds a customer's own words (`Invoice from A&B "Shop" <Tienda>`) then broke the attribute or added markup, and a subject cannot carry entities of its own. All four values are now escaped with `ERB::Util.html_escape`. The body stays as the Builder made it. A custom layout (`layout_path:`) must escape these values itself.
6
+
1
7
  ## [0.4.0] - 2026-05-08
2
8
 
3
9
  A polish-and-correctness release. Adds five new DSL helpers, a comprehensive Minitest 6 test suite (100% line coverage), and fixes nine real-world bugs that surfaced after running every email shape through Mailcatcher and inspecting the rendered HTML, plaintext, headers, and attachments end-to-end. The bug fixes are the headline — most of them silently degraded plaintext quality, deliverability, or accessibility before; downstream apps inherit the fixes for free on upgrade.
@@ -54,8 +54,18 @@ module Goodmail
54
54
  # Rails intentionally accepts arbitrary message headers and filters only
55
55
  # framework-only render keys internally; Goodmail should follow that shape
56
56
  # instead of maintaining a narrow whitelist of envelope fields.
57
- # Source:
58
- # https://github.com/rails/rails/blob/debbd18c562df17d01944c475e9291d927910b58/actionmailer/lib/action_mailer/base.rb#L972-L976
57
+ #
58
+ # Do not validate `to`, `from`, or `reply_to` here. Goodmail owns rendering
59
+ # and the mechanical Action Mailer handoff, while address acceptance belongs
60
+ # to the caller and its delivery provider. For example, SES requires ASCII
61
+ # addresses shaped as `UserName@[SubDomain.]Domain.TopLevelDomain`; another
62
+ # adapter may support SMTPUTF8 or intentionally use local test domains.
63
+ #
64
+ # Sources:
65
+ # - Rails header handling:
66
+ # https://github.com/rails/rails/blob/debbd18c562df17d01944c475e9291d927910b58/actionmailer/lib/action_mailer/base.rb#L972-L976
67
+ # - SES-specific recipient and SMTPUTF8 constraints:
68
+ # https://docs.aws.amazon.com/ses/latest/APIReference/API_SendRawEmail.html
59
69
  def self.action_mailer_headers(headers)
60
70
  headers.each_with_object({}) do |(key, value), result|
61
71
  next if render_header_key?(key)
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta name="viewport" content="width=device-width" />
5
5
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
- <title><%= subject %></title>
6
+ <title><%= ERB::Util.html_escape(subject) %></title>
7
7
  <style type="text/css">
8
8
  /* Base Styles */
9
9
  img {
@@ -162,7 +162,7 @@
162
162
 
163
163
  <!-- Hidden Preheader Text -->
164
164
  <span style="display:none !important; font-size:1px; color:#ffffff; line-height:1px; max-height:0px; max-width:0px; opacity:0; overflow:hidden;">
165
- <%= preheader || subject %>
165
+ <%= ERB::Util.html_escape(preheader || subject) %>
166
166
  </span>
167
167
 
168
168
  <table class="body-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6">
@@ -192,7 +192,7 @@
192
192
  <table class="main" width="100%" cellpadding="0" cellspacing="0" itemprop="action" itemscope itemtype="http://schema.org/ConfirmAction" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; border-radius: 3px; background-color: #fff; margin: 0; border: 1px solid #e9e9e9;" bgcolor="#fff">
193
193
  <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
194
194
  <td class="content-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 30px;" valign="top">
195
- <meta itemprop="name" content="<%= subject %>" />
195
+ <meta itemprop="name" content="<%= ERB::Util.html_escape(subject) %>" />
196
196
  <table width="100%" cellpadding="0" cellspacing="0" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
197
197
  <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
198
198
  <td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top">
@@ -228,7 +228,7 @@
228
228
  <% if config.show_footer_unsubscribe_link && defined?(unsubscribe_url) && unsubscribe_url.present? %>
229
229
  <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
230
230
  <td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; text-align: center; margin: 0; padding: 0 0 10px; color: #999;" align="center" valign="top">
231
- <a href="<%= unsubscribe_url %>" style="color: #999;"><%= config.footer_unsubscribe_link_text %></a>
231
+ <a href="<%= ERB::Util.html_escape(unsubscribe_url) %>" style="color: #999;"><%= config.footer_unsubscribe_link_text %></a>
232
232
  </td>
233
233
  </tr>
234
234
  <% end %>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Goodmail
4
- VERSION = "0.4.0"
4
+ VERSION = "0.4.1"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: goodmail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - rameerez
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-05-21 00:00:00.000000000 Z
10
+ date: 2026-10-24 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: premailer-rails