diff --git a/app/assets/images/email/README.md b/app/assets/images/email/README.md index c93a28f3b..bb68f70d0 100644 --- a/app/assets/images/email/README.md +++ b/app/assets/images/email/README.md @@ -17,5 +17,10 @@ the mailer view to reference the new file. Never mutate an existing file. ## Email stylesheet The email CSS lives at `app/assets/stylesheets/email.css` — not in this -folder — but it's referenced by mailer layouts via the pipeline path -`email.css`. +folder. It's linked from mailer layouts via the pipeline path `email.css`, +and `premailer-rails` inlines the rules at delivery time using the +`:filesystem` and `:asset_pipeline` strategies (see +`config/initializers/premailer.rb`). + +⚠️ Never add a `` that resolves at open time — premailer handles +inlining, and external CSS requests are unreliable in email clients. diff --git a/app/views/shared_mailers/_social.html.haml b/app/views/shared_mailers/_social.html.haml index 86b9974be..7774650e0 100644 --- a/app/views/shared_mailers/_social.html.haml +++ b/app/views/shared_mailers/_social.html.haml @@ -8,14 +8,12 @@ %td %h5 Connect with us: - -# background-color is inlined on each link because email clients only - -# reliably render inline styles; see issue #2634 %p - %a{ href: "https://slack.codebar.io/", class: 'soc-btn sl', style: 'background-color: #2EB67D;' } Join us on Slack - %a{ href: "https://www.linkedin.com/company/codebarcommunity", class: "soc-btn li", style: 'background-color: #0077B5;' } Follow us on LinkedIn - %a{ href: "https://www.facebook.com/codebarHQ", class: 'soc-btn fb', style: 'background-color: #3B5998;' } Follow us on Facebook - %a{ href: "https://bsky.app/profile/codebar.bsky.social", class: "soc-btn bs", style: 'background-color: #1daced;' } Follow us on Bluesky - %a{ href: "https://www.youtube.com/channel/UCEYz232agE47GHUq8wneBCA", class: "soc-btn yt", style: 'background-color: #FF0000;' } Follow us on YouTube + %a{ href: "https://slack.codebar.io/", class: 'soc-btn sl' } Join us on Slack + %a{ href: "https://www.linkedin.com/company/codebarcommunity", class: "soc-btn li" } Follow us on LinkedIn + %a{ href: "https://www.facebook.com/codebarHQ", class: 'soc-btn fb' } Follow us on Facebook + %a{ href: "https://bsky.app/profile/codebar.bsky.social", class: "soc-btn bs" } Follow us on Bluesky + %a{ href: "https://www.youtube.com/channel/UCEYz232agE47GHUq8wneBCA", class: "soc-btn yt" } Follow us on YouTube diff --git a/config/initializers/premailer.rb b/config/initializers/premailer.rb index 7257df900..8430c09b2 100644 --- a/config/initializers/premailer.rb +++ b/config/initializers/premailer.rb @@ -1 +1,4 @@ -Premailer::Rails.config.merge!(preserve_styles: true) +Premailer::Rails.config.merge!( + preserve_styles: true, + strategies: [:filesystem, :asset_pipeline] +) diff --git a/spec/mailers/event_invitation_mailer_spec.rb b/spec/mailers/event_invitation_mailer_spec.rb index b2a94bfa2..5b202b588 100644 --- a/spec/mailers/event_invitation_mailer_spec.rb +++ b/spec/mailers/event_invitation_mailer_spec.rb @@ -90,4 +90,10 @@ expect(email.body.encoded).to include('Safe content') end end + + it_behaves_like 'email with social link colours' do + def send_email + described_class.invite_student(event, member, invitation).deliver_now + end + end end diff --git a/spec/mailers/feedback_request_mailer_spec.rb b/spec/mailers/feedback_request_mailer_spec.rb index b84eb4498..c5c7f0bbd 100644 --- a/spec/mailers/feedback_request_mailer_spec.rb +++ b/spec/mailers/feedback_request_mailer_spec.rb @@ -42,5 +42,11 @@ expect(email.subject).to eq(email_subject) expect(email.from).to eq(['meetings@codebar.io']) end + + it_behaves_like 'email with social link colours' do + def send_email + described_class.request_feedback(workshop, member, feedback_request).deliver_now + end + end end end diff --git a/spec/mailers/meeting_invitation_mailer_spec.rb b/spec/mailers/meeting_invitation_mailer_spec.rb index 9a8ea20e3..bdc9841ca 100644 --- a/spec/mailers/meeting_invitation_mailer_spec.rb +++ b/spec/mailers/meeting_invitation_mailer_spec.rb @@ -101,4 +101,10 @@ expect(mail.body.encoded).to match('hello@codebar.io') end end + + it_behaves_like 'email with social link colours' do + def send_email + described_class.invite(meeting, member, invitation).deliver_now + end + end end diff --git a/spec/mailers/virtual_workshop_invitation_mailer_spec.rb b/spec/mailers/virtual_workshop_invitation_mailer_spec.rb index ae13a5177..828807583 100644 --- a/spec/mailers/virtual_workshop_invitation_mailer_spec.rb +++ b/spec/mailers/virtual_workshop_invitation_mailer_spec.rb @@ -111,4 +111,10 @@ expect(email.body.encoded).to match("the virtual workshop on #{humanize_date(workshop.date_and_time, with_time: true)}") expect(email.body.encoded).to match(workshop.chapter.email) end + + it_behaves_like 'email with social link colours' do + def send_email + described_class.invite_student(workshop, member, invitation).deliver_now + end + end end diff --git a/spec/mailers/workshop_invitation_mailer_spec.rb b/spec/mailers/workshop_invitation_mailer_spec.rb index 1f52ba8a6..66a28e04d 100644 --- a/spec/mailers/workshop_invitation_mailer_spec.rb +++ b/spec/mailers/workshop_invitation_mailer_spec.rb @@ -110,14 +110,9 @@ expect(email.body.encoded).to match(workshop.chapter.email) end - it '#invite_student renders social links with inline background colours' do - # asserts on the template output before premailer runs, so the colours - # don't depend on email.css being resolved (see issue #2634) - mail = described_class.invite_student(workshop, member, invitation) - - html = mail.body.decoded - ['#2EB67D', '#0077B5', '#3B5998', '#1daced', '#FF0000'].each do |colour| - expect(html).to include("background-color: #{colour}") + it_behaves_like 'email with social link colours' do + def send_email + described_class.invite_student(workshop, member, invitation).deliver_now end end diff --git a/spec/support/shared_examples/behaves_like_email_with_social_links.rb b/spec/support/shared_examples/behaves_like_email_with_social_links.rb new file mode 100644 index 000000000..a0e308fbf --- /dev/null +++ b/spec/support/shared_examples/behaves_like_email_with_social_links.rb @@ -0,0 +1,16 @@ +RSpec.shared_examples 'email with social link colours' do + # rubocop:disable RSpec/MultipleExpectations + it 'inlines social link background colours from the stylesheet' do + send_email + + html = ActionMailer::Base.deliveries.last.html_part.body.decoded + expect(html).to include('background-color: #2EB67D') + expect(html).to include('background-color: #0077B5') + expect(html).to include('background-color: #3B5998') + expect(html).to include('background-color: #1daced') + # premailer normalises #FF0000 to 'red' + expect(html).to match(/background-color: (red|#FF0000)/i) + expect(html).not_to include('/assets/email.css') + end + # rubocop:enable RSpec/MultipleExpectations +end