FEATURE: Use group SMTP settings for sending user notification emails (initial) (#13220)

This PR changes the `UserNotification` class to send outbound `user_private_message` using the group's SMTP settings, but only if:

* The first allowed_group on the topic has SMTP configured and enabled
* SiteSetting.enable_smtp is true
* The group does not have IMAP enabled, if this is enabled the `GroupSMTPMailer` handles things

The email is sent using the group's `email_username` as both the `from` and `reply-to` address, so when the user replies from their email it will go through the group's SMTP inbox, which needs to have email forwarding set up to send the message on to a location (such as a hosted site email address like meta@discoursemail.com) where it can be POSTed into discourse's handle_mail route.

Also includes a fix to `EmailReceiver#group_incoming_emails_regex` to include the `group.email_username` so the group does not get a staged user created and invited to the topic (which was a problem for IMAP), as well as updating `Group.find_by_email` to find using the `email_username` as well for inbound emails with that as the TO address.

#### Note

This is safe to merge without impacting anyone seriously. If people had SMTP enabled for a group they would have IMAP enabled too currently, and that is a very small amount of users because IMAP is an alpha product, and also because the UserNotification change has a guard to make sure it is not used if IMAP is enabled for the group. The existing IMAP tests work, and I tested this functionality by manually POSTing replies to the SMTP address into my local discourse.

There will probably be more work needed on this, but it needs to be tested further in a real hosted environment to continue.
This commit is contained in:
Martin Brennan
2021-06-03 14:47:32 +10:00
committed by GitHub
parent 3249312c81
commit eb2c399445
11 changed files with 219 additions and 13 deletions

View File

@@ -707,7 +707,10 @@ class Group < ActiveRecord::Base
end
def self.find_by_email(email)
self.where("string_to_array(incoming_email, '|') @> ARRAY[?]", Email.downcase(email)).first
self.where(
"email_username = :email OR string_to_array(incoming_email, '|') @> ARRAY[:email]",
email: Email.downcase(email)
).first
end
def bulk_add(user_ids)
@@ -870,8 +873,17 @@ class Group < ActiveRecord::Base
}
end
def email_username_domain
email_username.split('@').last
end
def email_username_user
email_username.split('@').first
end
def email_username_regex
user, domain = email_username.split('@')
user = email_username_user
domain = email_username_domain
if user.present? && domain.present?
/^#{Regexp.escape(user)}(\+[^@]*)?@#{Regexp.escape(domain)}$/i
end

View File

@@ -1674,6 +1674,15 @@ class Topic < ActiveRecord::Base
# group if the group is present. If combined addresses is empty we do
# not need to do this check, and instead can proceed on to adding the
# from address.
#
# Will not include test1@gmail.com if the only IncomingEmail
# is:
#
# from: test1@gmail.com
# to: test+support@discoursemail.com
#
# Because we don't care about the from addresses and also the to address
# is not the email_username, which will be something like test1@gmail.com.
if group.present? && combined_addresses.any?
next if combined_addresses.none? { |address| address =~ group.email_username_regex }
end