discourse/app/mailers/group_smtp_mailer.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

123 lines
3.7 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
require_dependency 'email/message_builder'
class GroupSmtpMailer < ActionMailer::Base
include Email::BuildEmailHelper
def send_mail(from_group, to_address, post, cc_addresses = nil)
raise 'SMTP is disabled' if !SiteSetting.enable_smtp
op_incoming_email = post.topic.first_post.incoming_email
context_posts = Post
.where(topic_id: post.topic_id)
.where("post_number < ?", post.post_number)
.where(user_deleted: false)
.where(hidden: false)
.where(post_type: Post.types[:regular])
.order(created_at: :desc)
.limit(SiteSetting.email_posts_context)
.to_a
delivery_options = {
address: from_group.smtp_server,
port: from_group.smtp_port,
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.
2021-06-02 23:47:32 -05:00
domain: from_group.email_username_domain,
user_name: from_group.email_username,
password: from_group.email_password,
authentication: GlobalSetting.smtp_authentication,
enable_starttls_auto: from_group.smtp_ssl
}
user_name = post.user.username
if SiteSetting.enable_names && SiteSetting.display_name_on_email_from
user_name = post.user.name unless post.user.name.blank?
end
group_name = from_group.full_name.presence || from_group.name
build_email(
to_address,
message: post.raw,
url: post.url(without_slug: SiteSetting.private_email?),
post_id: post.id,
topic_id: post.topic_id,
context: context(context_posts),
username: post.user.username,
group_name: group_name,
allow_reply_by_email: true,
only_reply_by_email: true,
use_from_address_for_reply_to: SiteSetting.enable_smtp && from_group.smtp_enabled?,
private_reply: post.topic.private_message?,
participants: participants(post),
include_respond_instructions: true,
template: 'user_notifications.user_posted_pm',
use_topic_title_subject: true,
topic_title: op_incoming_email&.subject || post.topic.title,
add_re_to_subject: true,
locale: SiteSetting.default_locale,
delivery_method_options: delivery_options,
from: from_group.email_username,
from_alias: I18n.t('email_from', user_name: group_name, site_name: Email.site_title),
html_override: html_override(post, context_posts: context_posts),
cc: cc_addresses
)
end
private
def context(context_posts)
return "" if SiteSetting.private_email?
context = +""
if context_posts.size > 0
context << +"-- \n*#{I18n.t('user_notifications.previous_discussion')}*\n"
context_posts.each { |post| context << email_post_markdown(post, true) }
end
context
end
def email_post_markdown(post, add_posted_by = false)
FEATURE: Allow email image embed with secure media (#10563) This PR introduces a few important changes to secure media redaction in emails. First of all, two new site settings have been introduced: * `secure_media_allow_embed_images_in_emails`: If enabled we will embed secure images in emails instead of redacting them. * `secure_media_max_email_embed_image_size_kb`: The cap to the size of the secure image we will embed, defaulting to 1mb, so the email does not become too big. Max is 10mb. Works in tandem with `email_total_attachment_size_limit_kb`. `Email::Sender` will now attach images to the email based on these settings. The sender will also call `inline_secure_images` in `Email::Styles` after secure media is redacted and attachments are added to replace redaction messages with attached images. I went with attachment and `cid` URLs because base64 image support is _still_ flaky in email clients. All redaction of secure media is now handled in `Email::Styles` and calls out to `PrettyText.strip_secure_media` to do the actual stripping and replacing with placeholders. `app/mailers/group_smtp_mailer.rb` and `app/mailers/user_notifications.rb` no longer do any stripping because they are earlier in the pipeline than `Email::Styles`. Finally the redaction notice has been restyled and includes a link to the media that the user can click, which will show it to them if they have the necessary permissions. ![image](https://user-images.githubusercontent.com/920448/92341012-b9a2c380-f0ff-11ea-860e-b376b4528357.png)
2020-09-09 18:50:16 -05:00
result = +"#{post.raw}\n\n"
if add_posted_by
result << "#{I18n.t('user_notifications.posted_by', username: post.username, post_date: post.created_at.strftime("%m/%d/%Y"))}\n\n"
end
result
end
def html_override(post, context_posts: nil)
UserNotificationRenderer.render(
template: 'email/notification',
format: :html,
locals: {
context_posts: context_posts,
reached_limit: nil,
post: post,
in_reply_to_post: post.reply_to_post,
classes: Rtl.new(nil).css_class,
first_footer_classes: ''
}
)
end
def participants(post)
list = []
post.topic.allowed_groups.each do |g|
list.push("[#{g.name} (#{g.users.count})](#{Discourse.base_url}/groups/#{g.name})")
end
post.topic.allowed_users.each do |u|
if SiteSetting.prioritize_username_in_ux?
list.push("[#{u.username}](#{Discourse.base_url}/u/#{u.username_lower})")
else
list.push("[#{u.name.blank? ? u.username : u.name}](#{Discourse.base_url}/u/#{u.username_lower})")
end
end
list.join(', ')
end
end