2014-02-03 19:23:00 +00:00
|
|
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
2013-06-12 15:59:58 +00:00
|
|
|
|
2012-04-13 16:42:25 +00:00
|
|
|
require 'mail'
|
|
|
|
|
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
|
|
|
|
2014-12-27 14:07:49 +00:00
|
|
|
#attr['X-Powered-BY'] = 'Zammad - Support/Helpdesk (http://www.zammad.org/)'
|
|
|
|
attr['X-Mailer'] = 'Zammad Mail Service (1.x)'
|
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'
|
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
|
|
|
|
if !html_alternative && ( !attr[:attachments] || attr[:attachments].empty? )
|
|
|
|
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
|
2016-05-10 13:06:51 +00:00
|
|
|
if attr[:attachments]
|
|
|
|
attr[:attachments].each do |attachment|
|
|
|
|
next if attachment.class == Hash
|
|
|
|
next if attachment.preferences['Content-ID'].empty?
|
|
|
|
attachment = Mail::Part.new do
|
|
|
|
content_type attachment.preferences['Content-Type']
|
2016-05-17 09:55:12 +00:00
|
|
|
content_id "<#{attachment.preferences['Content-ID']}>"
|
2016-05-10 13:06:51 +00:00
|
|
|
content_disposition attachment.preferences['Content-Disposition'] || 'inline'
|
|
|
|
content_transfer_encoding 'binary'
|
|
|
|
body attachment.content.force_encoding('BINARY')
|
|
|
|
end
|
|
|
|
html_container.add_part attachment
|
|
|
|
end
|
|
|
|
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
|
|
|
|
if attr[:attachments]
|
|
|
|
attr[:attachments].each do |attachment|
|
2014-12-30 14:08:20 +00:00
|
|
|
if attachment.class == Hash
|
|
|
|
attachment['content-id'] = nil
|
|
|
|
mail.attachments[ attachment[:filename] ] = attachment
|
|
|
|
else
|
2016-05-10 13:06:51 +00:00
|
|
|
next if !attachment.preferences['Content-ID'].empty?
|
2016-05-17 09:55:12 +00:00
|
|
|
filename = attachment.filename
|
|
|
|
encoded_filename = Mail::Encodings.decode_encode filename, :encode
|
|
|
|
disposition = attachment.preferences['Content-Disposition'] || 'attachment'
|
|
|
|
content_type = attachment.preferences['Content-Type'] || 'application/octet-stream'
|
2014-12-30 14:08:20 +00:00
|
|
|
mail.attachments[attachment.filename] = {
|
2016-05-17 09:55:12 +00:00
|
|
|
content_disposition: "#{disposition}; filename=\"#{encoded_filename}\"",
|
|
|
|
content_type: "#{content_type}; filename=\"#{encoded_filename}\"",
|
2016-05-12 13:25:47 +00:00
|
|
|
content: attachment.content
|
2014-12-30 14:08:20 +00:00
|
|
|
}
|
|
|
|
end
|
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
|
|
|
|
|
|
|
=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)
|
|
|
|
|
2014-12-29 15:39:59 +00:00
|
|
|
return html if html =~ /<html>/i
|
|
|
|
|
2015-01-08 23:01:41 +00:00
|
|
|
css = "font-family:'Helvetica Neue', Helvetica, Arial, Geneva, sans-serif; font-size: 12px;"
|
2014-12-29 15:39:59 +00:00
|
|
|
|
|
|
|
html = <<HERE
|
|
|
|
<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
<head>
|
2014-12-29 23:31:57 +00:00
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
2015-01-08 23:01:41 +00:00
|
|
|
<style type="text/css">
|
2016-05-12 13:25:47 +00:00
|
|
|
body {
|
|
|
|
width: 90% !important;
|
|
|
|
-webkit-text-size-adjust: 90%;
|
|
|
|
-ms-text-size-adjust: 90%;
|
|
|
|
#{css};
|
|
|
|
}
|
|
|
|
img {
|
|
|
|
outline: none;
|
|
|
|
text-decoration: none;
|
|
|
|
-ms-interpolation-mode: bicubic;
|
|
|
|
}
|
|
|
|
a img {
|
|
|
|
border: none;
|
|
|
|
}
|
|
|
|
table td {
|
|
|
|
border-collapse: collapse;
|
|
|
|
}
|
|
|
|
table {
|
|
|
|
border-collapse: collapse;
|
|
|
|
mso-table-lspace: 0pt;
|
|
|
|
mso-table-rspace: 0pt;
|
|
|
|
border: none;
|
|
|
|
table-layout: auto;
|
|
|
|
display: block;
|
|
|
|
width: 100%;
|
|
|
|
overflow: auto;
|
|
|
|
word-break: keep-all;
|
|
|
|
}
|
|
|
|
p, table, div, td {
|
|
|
|
max-width: 600px;
|
|
|
|
}
|
|
|
|
table,
|
|
|
|
pre,
|
|
|
|
blockquote {
|
|
|
|
margin: 0 0 16px;
|
|
|
|
}
|
|
|
|
td, th {
|
|
|
|
padding: 7px 12px;
|
|
|
|
border: 1px solid hsl(0,0%,87%);
|
|
|
|
}
|
|
|
|
th {
|
|
|
|
font-weight: bold;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
tbody tr:nth-child(even) {
|
|
|
|
background: hsl(0,0%,97%);
|
|
|
|
}
|
|
|
|
col {
|
|
|
|
width: auto;
|
|
|
|
}
|
2016-05-20 11:44:02 +00:00
|
|
|
p {
|
|
|
|
margin: 0;
|
|
|
|
}
|
2016-05-12 13:25:47 +00:00
|
|
|
code {
|
|
|
|
border: none;
|
|
|
|
background: hsl(0,0%,97%);
|
2016-05-17 11:51:20 +00:00
|
|
|
white-space: pre-wrap;
|
2016-05-12 13:25:47 +00:00
|
|
|
}
|
|
|
|
blockquote {
|
|
|
|
padding: 8px 12px;
|
|
|
|
border-left: 5px solid #eee;
|
|
|
|
}
|
|
|
|
pre {
|
|
|
|
padding: 12px 15px;
|
|
|
|
font-size: 13px;
|
|
|
|
line-height: 1.45;
|
|
|
|
background: hsl(0,0%,97%);
|
|
|
|
white-space: pre-wrap;
|
|
|
|
border-radius: 3px;
|
|
|
|
border: none;
|
|
|
|
overflow: auto;
|
|
|
|
}
|
2015-01-08 23:01:41 +00:00
|
|
|
</style>
|
2014-12-29 15:39:59 +00:00
|
|
|
<head>
|
2014-12-29 17:21:41 +00:00
|
|
|
<body style="#{css}">#{html}</body>
|
2014-12-29 15:39:59 +00:00
|
|
|
</html>
|
|
|
|
HERE
|
|
|
|
|
|
|
|
html
|
|
|
|
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-05-20 11:44:02 +00:00
|
|
|
html.gsub!('<blockquote type="cite">', '<blockquote type="cite" style="border-left: 2px solid blue; margin: 0px; padding: 8px 12px 8px 12px;">')
|
|
|
|
html.gsub('<p>', '<p style="margin: 0;">')
|
2016-02-10 23:09:27 +00:00
|
|
|
|
|
|
|
end
|
|
|
|
|
2015-04-27 14:15:29 +00:00
|
|
|
end
|