FEATURE: Allow sending group SMTP emails with from alias (#15687)

This commit allows group SMTP emails to be sent with a
different from email address that has been set up as an
alias in the email provider. Emails from the alias will
be grouped correctly using Message-IDs in the mail client,
and replies to the alias go into the correct group inbox.
This commit is contained in:
Martin Brennan 2022-02-07 13:52:01 +10:00 committed by GitHub
parent 454d3740b4
commit 0a738bd5bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 71 additions and 9 deletions

View File

@ -37,6 +37,7 @@ export default Component.extend({
EmberObject.create({
email_username: this.group.email_username,
email_password: this.group.email_password,
email_from_alias: this.group.email_from_alias,
smtp_server: this.group.smtp_server,
smtp_port: (this.group.smtp_port || "").toString(),
smtp_ssl: this.group.smtp_ssl,
@ -73,6 +74,7 @@ export default Component.extend({
smtp_port: this.form.smtp_port,
smtp_ssl: this.form.smtp_ssl,
email_username: this.form.email_username,
email_from_alias: this.form.email_from_alias,
email_password: this.form.email_password,
});
})

View File

@ -243,6 +243,7 @@ const Group = RestModel.extend({
imap_mailbox_name: this.imap_mailbox_name,
imap_enabled: this.imap_enabled,
email_username: this.email_username,
email_from_alias: this.email_from_alias,
email_password: this.email_password,
flair_icon: null,
flair_upload_id: null,

View File

@ -45,5 +45,5 @@
</div>
<br>
{{group-manage-save-button model=group disabled=(not emailSettingsValid) beforeSave=beforeSave afterSave=afterSave tabindex="14"}}
{{group-manage-save-button model=group disabled=(not emailSettingsValid) beforeSave=beforeSave afterSave=afterSave tabindex="15"}}
</div>

View File

@ -8,11 +8,11 @@
<div class="control-group">
<label for="smtp_server">{{i18n "groups.manage.email.credentials.smtp_server"}}</label>
{{input type="text" name="smtp_server" value=form.smtp_server tabindex="3" onChange=(action "resetSettingsValid")}}
{{input type="text" name="smtp_server" value=form.smtp_server tabindex="4" onChange=(action "resetSettingsValid")}}
</div>
<label for="enable_ssl">
{{input type="checkbox" checked=form.smtp_ssl id="enable_ssl" tabindex="5" onChange=(action "resetSettingsValid")}}
{{input type="checkbox" checked=form.smtp_ssl id="enable_ssl" tabindex="6" onChange=(action "resetSettingsValid")}}
{{i18n "groups.manage.email.credentials.smtp_ssl"}}
</label>
</div>
@ -25,7 +25,15 @@
<div class="control-group">
<label for="smtp_port">{{i18n "groups.manage.email.credentials.smtp_port"}}</label>
{{input type="text" name="smtp_port" value=form.smtp_port tabindex="4" onChange=(action "resetSettingsValid" form.smtp_port)}}
{{input type="text" name="smtp_port" value=form.smtp_port tabindex="5" onChange=(action "resetSettingsValid" form.smtp_port)}}
</div>
</div>
<div>
<div class="control-group">
<label for="from_alias">{{i18n "groups.manage.email.settings.from_alias"}}</label>
{{input type="text" name="from_alias" id="from_alias" value=form.email_from_alias onChange=(action "resetSettingsValid") tabindex="3"}}
<p>{{i18n "groups.manage.email.settings.from_alias_hint"}}</p>
</div>
</div>
</form>
@ -43,7 +51,7 @@
action=(action "testSmtpSettings")
icon="cog"
label="groups.manage.email.test_settings"
tabindex="6"
tabindex="7"
title="groups.manage.email.settings_required"
}}

View File

@ -106,6 +106,8 @@ acceptance(
await fillIn('input[name="username"]', "myusername@gmail.com");
await fillIn('input[name="password"]', "password@gmail.com");
await fillIn("#from_alias", "akasomegroup@example.com");
await click(".test-smtp-settings");
assert.ok(exists(".smtp-settings-ok"), "tested settings are ok");

View File

@ -252,7 +252,7 @@ table.group-category-permissions {
.group-imap-email-settings {
.groups-form {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-columns: 1fr 1fr 1fr;
margin-bottom: 0;
&.groups-form-imap {

View File

@ -713,6 +713,7 @@ class GroupsController < ApplicationController
:imap_updated_at,
:email_username,
:email_password,
:email_from_alias,
:primary_group,
:visibility_level,
:members_visibility_level,

View File

@ -48,7 +48,7 @@ class GroupSmtpMailer < ActionMailer::Base
add_re_to_subject: true,
locale: SiteSetting.default_locale,
delivery_method_options: delivery_options,
from: from_group.email_username,
from: from_group.smtp_from_address,
from_alias: I18n.t('email_from_without_site', user_name: group_name),
html_override: html_override(post),
cc: cc_addresses

View File

@ -110,7 +110,8 @@ class Group < ActiveRecord::Base
"imap_port",
"imap_ssl",
"email_username",
"email_password"
"email_password",
"email_from_alias"
]
ALIAS_LEVELS = {
@ -290,6 +291,10 @@ class Group < ActiveRecord::Base
end
end
def smtp_from_address
self.email_from_alias.present? ? self.email_from_alias : self.email_username
end
def downcase_incoming_email
self.incoming_email = (incoming_email || "").strip.downcase.presence
end
@ -708,7 +713,9 @@ class Group < ActiveRecord::Base
def self.find_by_email(email)
self.where(
"email_username = :email OR string_to_array(incoming_email, '|') @> ARRAY[:email]",
"email_username = :email OR
string_to_array(incoming_email, '|') @> ARRAY[:email] OR
email_from_alias = :email",
email: Email.downcase(email)
).first
end
@ -1128,6 +1135,7 @@ end
# imap_enabled :boolean default(FALSE)
# imap_updated_at :datetime
# imap_updated_by_id :integer
# email_from_alias :string
#
# Indexes
#

View File

@ -32,6 +32,7 @@ class GroupShowSerializer < BasicGroupSerializer
:imap_updated_by,
:email_username,
:email_password,
:email_from_alias,
:imap_last_error,
:imap_old_emails,
:imap_new_emails,

View File

@ -754,6 +754,8 @@ en:
title: "Settings"
allow_unknown_sender_topic_replies: "Allow unknown sender topic replies."
allow_unknown_sender_topic_replies_hint: "Allows unknown senders to reply to group topics. If this is not enabled, replies from email addresses not already invited to the topic will create a new topic."
from_alias: "From Alias"
from_alias_hint: "Alias to use as the from address when sending group SMTP emails. Note this may not be supported by all mail providers, please consult your mail provider's documentation."
mailboxes:
synchronized: "Synchronized Mailbox"
none_found: "No mailboxes were found in this email account."

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddEmailFromAliasToGroups < ActiveRecord::Migration[6.1]
def change
add_column :groups, :email_from_alias, :string, null: true
end
end

View File

@ -1225,6 +1225,23 @@ describe Group do
expect(group.smtp_updated_by).to eq(user)
end
it "records the change for singular setting changes" do
group.update(
smtp_port: 587,
smtp_ssl: true,
smtp_server: "smtp.gmail.com",
email_username: "test@gmail.com",
email_password: "password",
)
group.record_email_setting_changes!(user)
group.reload
old_updated_at = group.smtp_updated_at
group.update(email_from_alias: "somealias@gmail.com")
group.record_email_setting_changes!(user)
expect(group.reload.smtp_updated_at).not_to eq_time(old_updated_at)
end
it "enables imap and records the change" do
group.update(
imap_port: 587,
@ -1314,5 +1331,12 @@ describe Group do
expect(Group.find_by_email("support@test.com")).to eq(group)
expect(Group.find_by_email("nope@test.com")).to eq(nil)
end
it "finds the group by its email_from_alias" do
group.update!(email_username: "abc@test.com", email_from_alias: "somealias@test.com")
expect(Group.find_by_email("abc@test.com")).to eq(group)
expect(Group.find_by_email("somealias@test.com")).to eq(group)
expect(Group.find_by_email("nope@test.com")).to eq(nil)
end
end
end

View File

@ -221,6 +221,12 @@
"null"
]
},
"email_from_alias": {
"type": [
"string",
"null"
]
},
"email_password": {
"type": [
"string",