discourse/lib/email.rb
Martin Brennan 3b13f1146b
FIX: Add random suffix to outbound Message-ID for email (#15179)
Currently the Message-IDs we send out for outbound email
are not unique; for a post they look like:

topic/TOPIC_ID/POST_ID@HOST

And for a topic they look like:

topic/TOPIC_ID@HOST

This commit changes the outbound Message-IDs to also have
a random suffix before the host, so the new format is
like this:

topic/TOPIC_ID/POST_ID.RANDOM_SUFFIX@HOST

Or:

topic/TOPIC_ID.RANDOM_SUFFIX@HOST

This should help with email deliverability. This change
is backwards-compatible, the old Message-ID format will
still be recognized in the mail receiver flow, so people
will still be able to reply using Message-IDs, In-Reply-To,
and References headers that have already been sent.

This commit also refactors Message-ID related logic
to a central location, and adds judicious amounts of
tests and documentation.
2021-12-06 10:34:39 +10:00

67 lines
1.3 KiB
Ruby

# frozen_string_literal: true
require 'mail'
module Email
def self.is_valid?(email)
return false unless String === email
!!(EmailValidator.email_regex =~ email)
end
def self.downcase(email)
return email unless Email.is_valid?(email)
email.downcase
end
def self.obfuscate(email)
return email if !Email.is_valid?(email)
first, _, last = email.rpartition('@')
# Obfuscate each last part, except tld
last = last.split('.')
tld = last.pop
last.map! { |part| obfuscate_part(part) }
last << tld
"#{obfuscate_part(first)}@#{last.join('.')}"
end
def self.cleanup_alias(name)
name ? name.gsub(/[:<>,"]/, '') : name
end
def self.extract_parts(raw)
mail = Mail.new(raw)
text = nil
html = nil
if mail.multipart?
text = mail.text_part
html = mail.html_part
elsif mail.content_type.to_s["text/html"]
html = mail
else
text = mail
end
[text&.decoded, html&.decoded]
end
def self.site_title
SiteSetting.email_site_title.presence || SiteSetting.title
end
private
def self.obfuscate_part(part)
if part.size < 3
"*" * part.size
elsif part.size < 5
part[0] + "*" * (part.size - 1)
else
part[0] + "*" * (part.size - 2) + part[-1]
end
end
end