WORDPRESS FIX / EMAIL IMAGES

Email Logo Not Showing? Your Firewall May Be Blocking It

Your site's emails arrive, but the logo is a broken image, even though it loads fine in your browser. If a firewall rule blocks scripts and scanners, the email service's image fetcher may be what it is blocking.

Or call or text (502) 387-1142
5.0 23 Google reviews
25+Years building websites
1Person, start to finish
The Old Mill Venue website on a desk monitor
The Allied Plumbing website on a desk monitor
The Field of Screams Kentucky website on a desk monitor
Recent work · live site
Old Mill Venue
Visit oldmillvenue.com

Websites I have built for Kentucky businesses

  • Kentucky Peerless Distilling logo
  • Heimerdinger Cutlery logo
  • Vendome Copper & Brass Works logo
  • Justin Gooch Law logo
  • Allied Plumbing logo
  • Cardinal Wings Aviation logo
  • HogMatch logo
  • Field of Screams Kentucky logo
  • Lakeside Oasis RV Park logo
  • Legacy Cooperages logo
  • Dr. Stephanie Moore MD logo
  • Old Mill Venue logo
  • Todd Lewis Law logo
  • Lakeside Boat Storage logo
  • The Island Earth logo
  • Aerial Photography Louisville logo
  • Cru Bear logo
  • Arrow Aerial logo

The short answer

Many email services fetch the images in your messages from your site through their own servers, instead of the reader’s mail app fetching them directly. Those servers identify themselves with technical user agents. If your firewall has a rule that blocks requests from scripts and scanners by user agent, it can block the email service too, and the logo arrives as a broken image. Exempt plain image files from that rule and the logo comes back, without weakening anything else.

How I found it

A test inquiry from my own contact form arrived without the logo at the top. The image address was right, and it loaded instantly in a browser. My site sends its mail through Brevo, and Brevo’s image proxy fetches images with the user agent Go-http-client/2.0.

My Cloudflare firewall had a custom rule that blocks requests with an empty user agent, or one containing strings like go-http-client and python-requests, because that is what most vulnerability scanners send. The firewall’s event log showed the logo request, with that user agent, blocked by that rule. The rule was doing exactly what I wrote it to do.

How to check your own site

  1. Open an email from your site and copy the address of the broken image, from the message source if your mail app hides it.
  2. In Cloudflare, open the Security events log and filter by that path.
  3. Look at the user agent on the blocked request and the rule that blocked it.
  4. Confirm it from your own computer by asking for the image with the same user agent.
curl -sI -A "Go-http-client/2.0" \
  https://example.com/wp-content/uploads/logo.png

A 403 means the firewall is blocking it. A 200 means the image is reachable and the problem is somewhere else. If you use a different email service, its image fetcher will have a different user agent; the events log shows you which one.

Why the rule blocks these user agents at all

Blocking empty and script user agents is a cheap filter that works. Real visitors use browsers, and browsers always send a full user agent. Much of the automated traffic probing WordPress sites for weak spots comes from tools that announce themselves as go-http-client, python-requests or nothing at all. So the rule stops a lot of junk with very few false alarms. The email image fetcher is one of those few, and it is easy to miss, because nothing on the website looks broken.

The same rule can catch your own tools. Any script, monitor or connector you run against your site should send its own descriptive user agent, so it is never mistaken for a scanner.

The fix: exempt images, not the user agent

The tempting fix is to take go-http-client out of the rule. Do not. Plenty of real attack tools use that user agent, and the rule is doing its job on everything except your images. Add an exception for plain image files under /wp-content/, where WordPress keeps its uploads. In Cloudflare’s rule expression, add this to the end:

and not (
  starts_with(http.request.uri.path, "/wp-content/")
  and http.request.uri.path.extension in
    {"png" "jpg" "jpeg" "gif" "webp" "avif" "svg" "ico"}
)

If your rule is a list of conditions joined with or, wrap the original expression in brackets first and then add the exception. In Cloudflare’s rule language and is evaluated before or, so without the brackets the exception only attaches to the last condition.

Why this is safe:

  • It only matches image extensions, so a PHP file planted in the uploads folder is still blocked.
  • It only covers /wp-content/, so the rest of the site keeps its protection.
  • Everything else in the rule, such as blocks on probes for configuration files, is unchanged.

Check the fix

Run three requests with the same user agent. Only the first should get through:

UA="Go-http-client/2.0"

# the logo, as the email service sees it: expect 200
curl -sI -A "$UA" https://example.com/wp-content/uploads/logo.png

# the home page with the same agent: expect 403
curl -sI -A "$UA" https://example.com/

# a script in the uploads folder: expect 403
curl -sI -A "$UA" https://example.com/wp-content/uploads/x.php

Then send yourself a new test email. Check the new one, not the old one that showed the broken image.

Things to watch for

  • If your uploads are not in /wp-content/ because the site uses a custom folder, the exception needs that path instead.
  • A firewall on the server itself, such as ModSecurity, can carry the same kind of rule. If Cloudflare is not blocking the image and it still fails, check the server’s log. On my site it was Cloudflare alone.
  • If you copy the same rule across several sites, fix all of them. I run the same rule on the sites I host, so the exception went onto every one the same evening. A rule cloned later from the old text brings the problem straight back.

This is the kind of quiet fault I track down as a WordPress developer in Louisville: nothing is broken in WordPress, and the cause is two layers away from where the symptom shows.

Frequently asked questions

Why does the logo load in my browser but not in the email?

Your browser sends a normal browser user agent. The email service’s image fetcher sends a technical one, and that is what the firewall rule matches.

Should I attach the logo to the email instead?

Embedding the image works, but it makes every message heavier and some mail apps show it as an attachment. Fixing the firewall rule is the cleaner answer.

Will this exception let attackers in?

It only allows image files under /wp-content/. Scripts, configuration files and every other path are still checked by the rule.

Is this only a Brevo problem?

No. Any service that fetches images from a server rather than a person’s browser can trip a rule that blocks by user agent. Brevo is the one I found it with.

Why not allow the email service by IP address?

You could, but services change their addresses without telling you, and the list would need keeping up to date. An exception by folder and file type does not need maintaining.

EMAILS LOOK BROKEN?

Send me one. I will trace it.

Form emails that go missing or arrive broken are WordPress repairs I do regularly. If you suspect authentication, first check your SPF, DKIM and DMARC records. Call me at (502) 387-1142, or start with WordPress repair.

Similar Posts