2016-10-19 03:11:36 +00:00
|
|
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
2014-12-27 15:25:58 +00:00
|
|
|
module Channel::EmailBuild
|
2012-04-13 16:42:25 +00:00
|
|
|
|
2014-12-27 14:07:49 +00:00
|
|
|
=begin
|
|
|
|
|
2014-12-27 15:25:58 +00:00
|
|
|
mail = Channel::EmailBuild.build(
|
2016-02-10 23:09:27 +00:00
|
|
|
from: 'sender@example.com',
|
|
|
|
to: 'recipient@example.com',
|
|
|
|
body: 'somebody with some text',
|
|
|
|
content_type: 'text/plain',
|
2014-12-27 14:07:49 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
2014-12-29 23:25:57 +00:00
|
|
|
def self.build(attr, notification = false)
|
2012-04-13 16:42:25 +00:00
|
|
|
mail = Mail.new
|
|
|
|
|
|
|
|
# set organization
|
|
|
|
organization = Setting.get('organization')
|
2015-04-30 18:16:25 +00:00
|
|
|
if organization
|
2012-07-28 16:36:47 +00:00
|
|
|
mail['Organization'] = organization.to_s
|
2012-04-13 16:42:25 +00:00
|
|
|
end
|
2012-08-06 06:29:54 +00:00
|
|
|
|
2012-04-13 16:42:25 +00:00
|
|
|
# notification
|
|
|
|
if notification
|
2015-09-20 00:16:22 +00:00
|
|
|
attr['X-Loop'] = 'yes'
|
|
|
|
attr['Precedence'] = 'bulk'
|
|
|
|
attr['Auto-Submitted'] = 'auto-generated'
|
|
|
|
attr['X-Auto-Response-Suppress'] = 'All'
|
2012-04-13 16:42:25 +00:00
|
|
|
end
|
2012-08-06 06:29:54 +00:00
|
|
|
|
2016-11-23 14:28:12 +00:00
|
|
|
attr['X-Powered-By'] = 'Zammad - Helpdesk/Support (https://zammad.org/)'
|
|
|
|
attr['X-Mailer'] = 'Zammad Mail Service'
|
2012-08-06 06:29:54 +00:00
|
|
|
|
2012-04-13 16:42:25 +00:00
|
|
|
# set headers
|
2014-12-27 14:07:49 +00:00
|
|
|
attr.each do |key, value|
|
|
|
|
next if key.to_s == 'attachments'
|
|
|
|
next if key.to_s == 'body'
|
|
|
|
next if key.to_s == 'content_type'
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-01-15 17:22:57 +00:00
|
|
|
mail[key.to_s] = if value && value.class != Array
|
|
|
|
value.to_s
|
|
|
|
else
|
|
|
|
value
|
|
|
|
end
|
2014-12-27 14:07:49 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# add html part
|
|
|
|
if attr[:content_type] && attr[:content_type] == 'text/html'
|
2014-12-30 14:08:20 +00:00
|
|
|
html_alternative = Mail::Part.new do
|
2014-12-27 14:07:49 +00:00
|
|
|
content_type 'text/html; charset=UTF-8'
|
2014-12-29 15:39:59 +00:00
|
|
|
|
|
|
|
# complete check
|
2016-02-10 23:09:27 +00:00
|
|
|
html_document = Channel::EmailBuild.html_complete_check(attr[:body])
|
2014-12-29 15:39:59 +00:00
|
|
|
|
2015-01-08 14:55:52 +00:00
|
|
|
body html_document
|
2012-04-13 16:42:25 +00:00
|
|
|
end
|
2014-12-27 14:07:49 +00:00
|
|
|
|
|
|
|
# generate plain part
|
2014-12-27 15:25:58 +00:00
|
|
|
attr[:body] = attr[:body].html2text
|
2012-04-13 16:42:25 +00:00
|
|
|
end
|
|
|
|
|
2014-12-27 14:07:49 +00:00
|
|
|
# add plain text part
|
2014-12-30 14:08:20 +00:00
|
|
|
text_alternative = Mail::Part.new do
|
2014-12-27 14:07:49 +00:00
|
|
|
content_type 'text/plain; charset=UTF-8'
|
2012-04-13 16:42:25 +00:00
|
|
|
body attr[:body]
|
|
|
|
end
|
|
|
|
|
2014-12-30 14:08:20 +00:00
|
|
|
# build email without any attachments
|
2017-11-23 08:09:44 +00:00
|
|
|
if !html_alternative && attr[:attachments].blank?
|
2014-12-30 14:08:20 +00:00
|
|
|
mail.content_type 'text/plain; charset=UTF-8'
|
|
|
|
mail.body attr[:body]
|
|
|
|
return mail
|
|
|
|
end
|
|
|
|
|
|
|
|
# build email with attachments
|
|
|
|
alternative_bodies = Mail::Part.new { content_type 'multipart/alternative' }
|
|
|
|
alternative_bodies.add_part text_alternative
|
|
|
|
|
|
|
|
if html_alternative
|
|
|
|
html_container = Mail::Part.new { content_type 'multipart/related' }
|
|
|
|
html_container.add_part html_alternative
|
|
|
|
|
|
|
|
# place to add inline attachments related to html alternative
|
2017-11-23 08:09:44 +00:00
|
|
|
attr[:attachments]&.each do |attachment|
|
|
|
|
next if attachment.class == Hash
|
|
|
|
next if attachment.preferences['Content-ID'].blank?
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-11-23 08:09:44 +00:00
|
|
|
attachment = Mail::Part.new do
|
|
|
|
content_type attachment.preferences['Content-Type']
|
|
|
|
content_id "<#{attachment.preferences['Content-ID']}>"
|
|
|
|
content_disposition attachment.preferences['Content-Disposition'] || 'inline'
|
|
|
|
content_transfer_encoding 'binary'
|
|
|
|
body attachment.content.force_encoding('BINARY')
|
2016-05-10 13:06:51 +00:00
|
|
|
end
|
2017-11-23 08:09:44 +00:00
|
|
|
html_container.add_part attachment
|
2016-05-10 13:06:51 +00:00
|
|
|
end
|
|
|
|
alternative_bodies.add_part html_container
|
2014-12-30 14:08:20 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
mail.add_part alternative_bodies
|
|
|
|
|
2012-04-13 16:42:25 +00:00
|
|
|
# add attachments
|
2017-11-23 08:09:44 +00:00
|
|
|
attr[:attachments]&.each do |attachment|
|
|
|
|
if attachment.class == Hash
|
|
|
|
attachment['content-id'] = nil
|
2018-04-16 09:58:03 +00:00
|
|
|
mail.attachments[attachment[:filename]] = attachment
|
2017-11-23 08:09:44 +00:00
|
|
|
else
|
|
|
|
next if attachment.preferences['Content-ID'].present?
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-11-23 08:09:44 +00:00
|
|
|
filename = attachment.filename
|
|
|
|
encoded_filename = Mail::Encodings.decode_encode filename, :encode
|
|
|
|
disposition = attachment.preferences['Content-Disposition'] || 'attachment'
|
2018-04-16 09:58:03 +00:00
|
|
|
content_type = attachment.preferences['Content-Type'] || attachment.preferences['Mime-Type'] || 'application/octet-stream'
|
2017-11-23 08:09:44 +00:00
|
|
|
mail.attachments[attachment.filename] = {
|
|
|
|
content_disposition: "#{disposition}; filename=\"#{encoded_filename}\"",
|
2018-12-19 17:31:51 +00:00
|
|
|
content_type: "#{content_type}; filename=\"#{encoded_filename}\"",
|
|
|
|
content: attachment.content
|
2017-11-23 08:09:44 +00:00
|
|
|
}
|
2012-04-13 16:42:25 +00:00
|
|
|
end
|
|
|
|
end
|
2014-10-22 21:00:11 +00:00
|
|
|
mail
|
2012-04-13 16:42:25 +00:00
|
|
|
end
|
2014-12-29 15:39:59 +00:00
|
|
|
|
2016-11-25 12:43:28 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
quoted_in_one_line = Channel::EmailBuild.recipient_line('Somebody @ "Company"', 'some.body@example.com')
|
|
|
|
|
2016-12-12 14:06:01 +00:00
|
|
|
returns
|
2016-11-25 12:43:28 +00:00
|
|
|
|
|
|
|
'"Somebody @ \"Company\"" <some.body@example.com>'
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.recipient_line(realname, email)
|
2017-11-23 08:09:44 +00:00
|
|
|
return "#{realname} <#{email}>" if realname.match?(/^[A-z]+$/i)
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-11-25 12:43:28 +00:00
|
|
|
"\"#{realname.gsub('"', '\"')}\" <#{email}>"
|
|
|
|
end
|
|
|
|
|
2014-12-29 15:39:59 +00:00
|
|
|
=begin
|
|
|
|
|
2016-02-10 23:09:27 +00:00
|
|
|
Check if string is a complete html document. If not, add head and css styles.
|
|
|
|
|
|
|
|
full_html_document_string = Channel::EmailBuild.html_complete_check(html_string)
|
2014-12-29 15:39:59 +00:00
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.html_complete_check(html)
|
2016-02-10 23:09:27 +00:00
|
|
|
|
|
|
|
# apply mail client fixes
|
|
|
|
html = Channel::EmailBuild.html_mail_client_fixes(html)
|
|
|
|
|
2017-11-23 08:09:44 +00:00
|
|
|
return html if html.match?(/<html>/i)
|
2014-12-29 15:39:59 +00:00
|
|
|
|
2018-04-23 06:59:49 +00:00
|
|
|
html_email_body = File.read(Rails.root.join('app', 'views', 'mailer', 'application_wrapper.html.erb').to_s)
|
2018-04-10 19:15:52 +00:00
|
|
|
|
|
|
|
html_email_body.gsub!('###html_email_css_font###', Setting.get('html_email_css_font'))
|
|
|
|
|
2017-07-13 09:59:22 +00:00
|
|
|
# use block form because variable html could contain backslashes and e. g. '\1' that
|
|
|
|
# must not be handled as back-references for regular expressions
|
2018-04-10 19:15:52 +00:00
|
|
|
html_email_body.sub('###html###') { html }
|
2014-12-29 15:39:59 +00:00
|
|
|
end
|
2016-02-10 23:09:27 +00:00
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
Add/change markup to display html in any mail client nice.
|
|
|
|
|
|
|
|
html_string_with_fixes = Channel::EmailBuild.html_mail_client_fixes(html_string)
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.html_mail_client_fixes(html)
|
|
|
|
|
|
|
|
# https://github.com/martini/zammad/issues/165
|
2016-06-09 13:00:11 +00:00
|
|
|
new_html = html.gsub('<blockquote type="cite">', '<blockquote type="cite" style="border-left: 2px solid blue; margin: 0 0 16px; padding: 8px 12px 8px 12px;">')
|
2016-06-21 15:14:15 +00:00
|
|
|
new_html.gsub!(/<p>/mxi, '<p style="margin: 0;">')
|
|
|
|
new_html.gsub!(%r{</?hr>}mxi, '<hr style="margin-top: 6px; margin-bottom: 6px; border: 0; border-top: 1px solid #dfdfdf;">')
|
2016-05-20 12:16:36 +00:00
|
|
|
new_html
|
2016-02-10 23:09:27 +00:00
|
|
|
end
|
|
|
|
|
2015-04-27 14:15:29 +00:00
|
|
|
end
|