2013-06-10 15:33:37 -04:00
#
# A helper class to send an email. It will also handle a nil message, which it considers
# to be "do nothing". This is because some Mailers will decide not to do work for some
# reason. For example, emailing a user too frequently. A nil to address is also considered
# "do nothing"
#
# It also adds an HTML part for the plain text body
#
require_dependency 'email/renderer'
2013-07-02 14:13:46 -04:00
require 'uri'
2014-03-12 11:55:08 +01:00
require 'net/smtp'
2013-06-10 15:33:37 -04:00
2014-03-07 16:33:15 +01:00
SMTP_CLIENT_ERRORS = [ Net :: SMTPFatalError , Net :: SMTPSyntaxError ]
2013-06-10 15:33:37 -04:00
module Email
class Sender
def initialize ( message , email_type , user = nil )
@message = message
@email_type = email_type
@user = user
end
def send
2014-08-23 11:07:37 +02:00
return if SiteSetting . disable_emails
2014-02-14 13:06:21 -05:00
return skip ( I18n . t ( 'email_log.message_blank' ) ) if @message . blank?
return skip ( I18n . t ( 'email_log.message_to_blank' ) ) if @message . to . blank?
2013-11-28 17:20:56 -05:00
if @message . text_part
2014-02-14 13:06:21 -05:00
return skip ( I18n . t ( 'email_log.text_part_body_blank' ) ) if @message . text_part . body . to_s . blank?
2013-11-28 17:20:56 -05:00
else
2014-02-14 13:06:21 -05:00
return skip ( I18n . t ( 'email_log.body_blank' ) ) if @message . body . to_s . blank?
2013-11-28 17:20:56 -05:00
end
2013-06-10 15:33:37 -04:00
@message . charset = 'UTF-8'
opts = { }
renderer = Email :: Renderer . new ( @message , opts )
2013-11-29 12:21:21 -05:00
if @message . html_part
@message . html_part . body = renderer . html
else
2013-07-24 17:13:15 +10:00
@message . html_part = Mail :: Part . new do
content_type 'text/html; charset=UTF-8'
body renderer . html
end
2013-06-10 15:33:37 -04:00
end
2013-07-24 15:07:43 -04:00
@message . parts [ 0 ] . body = @message . parts [ 0 ] . body . to_s . gsub ( / \ [ \/ ?email-indent \ ] / , '' )
2013-07-22 15:06:37 -04:00
2013-06-10 15:33:37 -04:00
@message . text_part . content_type = 'text/plain; charset=UTF-8'
2013-06-25 11:35:26 -04:00
# Set up the email log
2013-06-13 18:11:10 -04:00
email_log = EmailLog . new ( email_type : @email_type ,
to_address : to_address ,
user_id : @user . try ( :id ) )
2013-07-02 14:13:46 -04:00
2013-07-08 11:48:40 -04:00
host = Email :: Sender . host_for ( Discourse . base_url )
2013-07-02 14:13:46 -04:00
2013-07-08 11:48:40 -04:00
topic_id = header_value ( 'X-Discourse-Topic-Id' )
post_id = header_value ( 'X-Discourse-Post-Id' )
reply_key = header_value ( 'X-Discourse-Reply-Key' )
if topic_id . present?
email_log . topic_id = topic_id
2014-06-13 15:42:14 -07:00
topic_identifier = " <topic/ #{ topic_id } @ #{ host } > "
@message . header [ 'In-Reply-To' ] = topic_identifier
@message . header [ 'References' ] = topic_identifier
# http://www.ietf.org/rfc/rfc2919.txt
2014-06-14 00:13:08 -07:00
list_id = " <topic. #{ topic_id } . #{ host } > "
@message . header [ 'List-ID' ] = list_id
2014-06-14 12:29:50 -04:00
topic = Topic . where ( id : topic_id ) . first
@message . header [ 'List-Archive' ] = topic . url if topic
2014-06-13 15:49:11 -07:00
end
if reply_key . present?
2014-06-14 12:29:50 -04:00
if @message . header [ 'Reply-To' ] =~ / \ <([^ \ >]+) \ > /
email = Regexp . last_match [ 1 ]
@message . header [ 'List-Post' ] = " <mailto: #{ email } > "
end
2013-07-08 11:48:40 -04:00
end
email_log . post_id = post_id if post_id . present?
email_log . reply_key = reply_key if reply_key . present?
2013-06-13 10:56:16 -04:00
2013-06-25 11:35:26 -04:00
# Remove headers we don't need anymore
@message . header [ 'X-Discourse-Topic-Id' ] = nil
@message . header [ 'X-Discourse-Post-Id' ] = nil
@message . header [ 'X-Discourse-Reply-Key' ] = nil
2014-03-07 16:33:15 +01:00
begin
@message . deliver
2014-03-09 23:06:54 +11:00
rescue * SMTP_CLIENT_ERRORS = > e
2014-03-07 16:33:15 +01:00
return skip ( e . message )
end
2013-06-25 11:35:26 -04:00
# Save and return the email log
2013-06-13 10:56:16 -04:00
email_log . save!
email_log
2013-06-10 15:33:37 -04:00
end
2014-02-14 13:06:21 -05:00
def to_address
@to_address || = begin
to = @message ? @message . to : nil
to . is_a? ( Array ) ? to . first : to
end
end
2013-07-08 11:48:40 -04:00
def self . host_for ( base_url )
2013-07-02 14:13:46 -04:00
host = " localhost "
if base_url . present?
begin
uri = URI . parse ( base_url )
host = uri . host . downcase if uri . host . present?
rescue URI :: InvalidURIError
end
end
2013-07-08 11:48:40 -04:00
host
end
2013-07-02 14:13:46 -04:00
2013-06-13 18:11:10 -04:00
private
2013-07-08 11:48:40 -04:00
def header_value ( name )
2013-06-13 18:11:10 -04:00
header = @message . header [ name ]
2013-07-08 11:48:40 -04:00
return nil unless header
header . value
2013-06-13 18:11:10 -04:00
end
2014-02-14 13:06:21 -05:00
def skip ( reason )
EmailLog . create ( email_type : @email_type ,
to_address : to_address ,
user_id : @user . try ( :id ) ,
skipped : true ,
skipped_reason : reason )
end
2013-06-10 15:33:37 -04:00
end
2013-07-24 17:13:15 +10:00
end