Incoming emails with signatures/tables/inline images rejected with “Access Denied”

I am seeing incoming emails rejected by Discourse with:

Email can not be processed: Access Denied

Incoming email itself appears to be working correctly. The message reaches the mail receiver, and SPF, DKIM and DMARC all pass. Discourse then processes it through Jobs::ProcessEmail.

The behaviour appears dependent on the MIME/body content:

  • simple/plain email → accepted
  • email containing an Outlook signature, table and/or inline images → rejected with Access Denied

The rejected email log shows the failure occurring in Email::Processor#process!.

Discourse application version:

4143157a17dc3ff63c909c64d0cf578243d38861

This installation was recently migrated/restored to another server, but incoming SMTP delivery itself is functioning and the behaviour seems specifically related to richer email bodies.

I can provide a sanitised raw MIME message and further IncomingEmail/Email::Receiver diagnostics if useful.

Update: I’ve now reproduced the cause of the Access Denied failures I was seeing and opened a PR:

The important part of my original observation was:

  • simple/plain incoming email → accepted
  • richer email containing embedded media → rejected with Access Denied

The rejected messages were being processed as staged/stranger users in a category which allows incoming email from strangers.

Since #42079, NewPostManager detects embedded media directly from the post content when image-size metadata is absent. This correctly causes these messages to enter the :contains_media review path.

However, before enqueueing the post for review, NewPostManager.default_handler performs the normal category topic-creation Guardian check.

For a staged incoming-email user, that check can fail even though Email::Receiver has already accepted the category’s stranger-email path and passed skip_validations.

That produces the error I was seeing:

Email::Receiver::InvalidPost: Access Denied

I added an end-to-end receiver regression test for a media-containing email from a stranger.

On current main, before the fix, the test reproduces:

Email::Receiver::InvalidPost: Access Denied

I also tested the same case immediately before #42079, where the incoming email is accepted, confirming this is a regression introduced by that change.

The PR preserves the intended media moderation rather than bypassing it. With the fix, the incoming email is queued as a ReviewableQueuedPost and its review reason remains:

contains_media

The relevant Email::Receiver and NewPostManager specs pass locally:

261 examples, 0 failures

So this appears to explain the Access Denied behaviour I reported above, including why plain emails worked while the richer messages containing embedded media did not.