Merge pull request #1525 from basecamp/mail-avatars

Render SVG avatars with regular HTML in emails since mail services won't support SVG
This commit is contained in:
Andy Smith
2025-11-07 14:00:07 -06:00
committed by GitHub
6 changed files with 76 additions and 14 deletions
+10
View File
@@ -19,6 +19,16 @@ module AvatarsHelper
end
end
def mail_avatar_tag(user, size: 48, **options)
if user.avatar.attached?
image_tag user_avatar_url(user), alt: user.name, class: "avatar", size: size, **options
else
tag.span class: "avatar", style: "background-color: #{avatar_background_color(user)};" do
user.initials
end
end
end
def avatar_preview_tag(user, hidden_for_screen_reader: false, **options)
tag.span class: class_names("avatar", options.delete(:class)),
aria: { hidden: hidden_for_screen_reader, label: user.name },
+14 -12
View File
@@ -43,27 +43,29 @@
width: 100% !important;
}
.avatar {
border-radius: 50%;
height: 2.75em;
margin-right: 0.2.75em;
max-height: 2.75em;
min-height: 2.75em;
overflow: hidden;
width: 2.75em;
}
.avatar__container {
padding-top: 1em;
vertical-align: top;
width: 3.25em;
}
.avatar {
border-radius: 50%;
color: white;
display: block;
font-weight: 600;
height: 2.75em;
line-height: 2.75em;
mso-line-height-rule: exactly;
overflow: hidden;
text-align: center;
width: 2.75em;
}
.btn {
background: #2d71e5;
border-color: #2d71e5;
border-radius: 3rem;
color: #ffffff !important;
color: white !important;
font-weight: 500;
padding: 0.5em 1em;
text-decoration: none;
@@ -1,8 +1,15 @@
<table class="notification">
<tr>
<td class="avatar__container"><%= image_tag user_avatar_url(notification.creator), alt: notification.creator.name, class: "avatar", size: 48 %></td>
<td>&nbsp;</td>
<td>
<%= render "notification/bundle_mailer/header", notification: notification %>
</td>
</tr>
<tr>
<td class="avatar__container">
<%= mail_avatar_tag(notification.creator) %>
</td>
<td class="what">
<%= render "notification/bundle_mailer/#{notification.source_type.underscore}/body", notification: notification %>
</td>
</tr>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

@@ -0,0 +1,44 @@
require "test_helper"
class Notification::BundleMailerTest < ActionMailer::TestCase
setup do
@user = users(:david)
@bundle = Notification::Bundle.create!(
user: @user,
starts_at: 1.hour.ago,
ends_at: 1.hour.from_now
)
end
test "renders avatar with initials in span when avatar is not attached" do
create_notification(@user)
email = Notification::BundleMailer.notification(@bundle)
assert_match /<span[^>]*class="avatar"[^>]*>/, email.html_part.body.to_s
assert_match /#{@user.initials}/, email.html_part.body.to_s
assert_match /style="background-color: #[A-F0-9]{6};?"/, email.html_part.body.to_s
end
test "renders avatar with external image URL when avatar is attached" do
@user.avatar.attach(
io: File.open(Rails.root.join("test", "fixtures", "files", "avatar.png")),
filename: "avatar.png",
content_type: "image/png"
)
create_notification(@user)
email = Notification::BundleMailer.notification(@bundle)
assert_match /<img[^>]*class="avatar"[^>]*>/, email.html_part.body.to_s
assert_match /<img[^>]*class="avatar"[^>]*src="[^"]*"/, email.html_part.body.to_s
assert_match /alt="#{@user.name}"/, email.html_part.body.to_s
end
private
def create_notification(user)
Notification.create!(user: user, creator: user, source: events(:logo_published), created_at: 30.minutes.ago)
end
end
@@ -1,6 +1,5 @@
class Notification::BundleMailerPreview < ActionMailer::Preview
def notification
ApplicationRecord.current_tenant = "1065895976"
Notification::BundleMailer.notification Notification::Bundle.take!
end
end