Email logos that survive Gmail
RailsFast gives transactional emails their own logo (email_logo_url in config/railsfast/railsfast.yml, separate from the web UI's logo_url), because Gmail destroys a typical web logo in two independent ways, and you'll never see either one coming: browsers and /rails/mailers previews render the broken asset perfectly. The damage only shows in a real Gmail inbox.
This convention comes from production: an app that mailed its web logo (a transparent WebP with a near-black wordmark) saw the email header arrive in Gmail as a solid black slab.
The two failure modes
1. Gmail re-encodes WebP to JPEG, and JPEG has no alpha channel. Gmail doesn't render WebP: it converts the file to JPEG on its image proxy, and since JPEG can't represent transparency, every transparent pixel is flattened to black. A dark wordmark on a black flatten is invisible. Sources: caniemail's WebP support table ("Converts file to jpg"), confirmed by the WebP team themselves.
2. Gmail's mobile dark mode repaints backgrounds, but never touches pixels inside an image. Switching to a transparent PNG fixes the WebP conversion, and then dark mode gets you: Gmail repaints the email's light background dark, your dark logo sits on it with no plate of its own, and disappears. Baking a light background into the image is the documented fix, because image pixels are the one thing dark mode won't repaint.
A dark logo on transparency dies both ways. That's why reusing logo_url for emails is a trap: the web UI wants transparency (navbar, footers, sidebars), and inboxes can't have it.
The convention
Emails get pixels of their own, wired through four pieces:
- A dedicated config key.
email_logo_urlunder Email Defaults inconfig/railsfast/railsfast.yml. The weblogo_urlkeeps its transparency; the email logo never inherits it. - A fully opaque PNG with the plate baked in.
public/email-logo.pngships painted on#f6f6f6, Goodmail's own page background, which is exactly what sits behind the email header. The plate is an invisible seam in light mode and a readable backdrop in dark mode. - Served from
public/. The asset deploys atomically with the config that points at it, with no CDN upload to forget.config/initializers/goodmail.rbresolves the relative path against the host each environment mails from, so mailer previews work onlocalhostand production emails gethttps://yourdomain.com/email-logo.png. An absolute URL (a CDN, say) passes through untouched. - ~4× sizing. Goodmail hardcodes the header
<img>at 20px tall, so the shipped PNG is 80px tall: 4× for retina screens, with a few pixels of baked-in padding so the plate stays visible around the mark.
Leaving email_logo_url blank skips the email header entirely. It deliberately does not fall back to logo_url, for all the reasons above. The template also pins the asset in a test: if public/email-logo.png ever reintroduces an alpha channel or palette transparency, the suite goes red.
Regenerating the logo
When you rebrand, regenerate the email logo from your master logo with ImageMagick (the same command lives in the railsfast.yml comment, right where you'll need it):
# 4x of Goodmail's 20px header height, opaque, #f6f6f6 plate baked in
magick logo.png -trim +repage -background '#f6f6f6' -alpha remove -alpha off \
-filter Lanczos -resize x72 -bordercolor '#f6f6f6' -border 12x4 \
-strip -define png:compression-level=9 public/email-logo.png
Then eyeball it at /rails/mailers/email_branding. The preview renders the shipped email logo, plus your web logo_url for comparison. Remember the preview can't show you Gmail's damage (browsers render transparency fine): to verify for real, send both to a Gmail account and check on mobile with dark mode on.