FIX: improve mailman email parsing (#21627)

https://meta.discourse.org/t/improving-mailman-email-parsing/253041

When mirroring a public mailling list which uses mailman, there were some cases where the incoming email was not associated to the proper user.

As it happens, for various (undertermined) reasons, the email from the sender is often not in the `From` header but can be in any of the following headers: `Reply-To`, `CC`, `X-Original-From`, `X-MailFrom`.

It might be in other headers as well, but those were the ones we found the most reliable.
This commit is contained in:
Régis Hanol
2023-05-19 10:33:48 +02:00
committed by GitHub
parent f62904715f
commit db9d998de3
8 changed files with 226 additions and 101 deletions

View File

@ -218,14 +218,6 @@ RSpec.describe Email::Receiver do
expect(IncomingEmail.last.error).to eq("RuntimeError")
end
it "matches the correct user" do
user = Fabricate(:user)
email_log = Fabricate(:email_log, to_address: user.email, user: user, bounce_key: nil)
email, name = Email::Receiver.new(email(:existing_user)).parse_from_field
expect(email).to eq("existing@bar.com")
expect(name).to eq("Foo Bar")
end
it "strips null bytes from the subject" do
expect do process(:null_byte_in_subject) end.to raise_error(
Email::Receiver::BadDestinationAddress,
@ -512,9 +504,8 @@ RSpec.describe Email::Receiver do
)
end
it "handles invalid from header" do
expect { process(:invalid_from_1) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("This email was sent with an invalid from header field.")
it "raises a NoSenderDetectedError when the From header can't be parsed" do
expect { process(:invalid_from_1) }.to raise_error(Email::Receiver::NoSenderDetectedError)
end
it "raises a NoSenderDetectedError when the From header doesn't contain an email address" do
@ -1996,6 +1987,38 @@ RSpec.describe Email::Receiver do
end
end
describe "mailman mirror" do
fab!(:category) { Fabricate(:mailinglist_mirror_category) }
it "uses 'from' email address" do
expect { process(:mailman_1) }.to change { Topic.count }
user = Topic.last.user
expect(user.email).to eq("some@one.com")
expect(user.name).to eq("Some One")
end
it "uses 'reply-to' email address" do
expect { process(:mailman_2) }.to change { Topic.count }
user = Topic.last.user
expect(user.email).to eq("some@one.com")
expect(user.name).to eq("Some")
end
it "uses 'x-mailfrom' email address and name from CC" do
expect { process(:mailman_3) }.to change { Topic.count }
user = Topic.last.user
expect(user.email).to eq("some@one.com")
expect(user.name).to eq("Some One")
end
it "uses 'x-original-from' email address" do
expect { process(:mailman_4) }.to change { Topic.count }
user = Topic.last.user
expect(user.email).to eq("some@one.com")
expect(user.name).to eq("Some")
end
end
describe "mailing list mirror" do
fab!(:category) { Fabricate(:mailinglist_mirror_category) }