pakyow-mailer 0.11.3 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/{pakyow-mailer/CHANGELOG.md → CHANGELOG.md} +0 -0
- data/LICENSE +4 -0
- data/{pakyow-mailer/README.md → README.md} +1 -2
- data/lib/pakyow/mailer/behavior/config.rb +32 -0
- data/lib/pakyow/mailer/framework.rb +38 -0
- data/lib/pakyow/mailer/helpers.rb +37 -0
- data/lib/pakyow/mailer/mailer.rb +120 -0
- data/lib/pakyow/mailer/plaintext.rb +123 -0
- data/lib/pakyow/mailer/style_inliner.rb +39 -0
- data/lib/pakyow/mailer.rb +10 -0
- metadata +78 -35
- data/pakyow-mailer/LICENSE +0 -20
- data/pakyow-mailer/lib/pakyow/mailer/config/mailer.rb +0 -16
- data/pakyow-mailer/lib/pakyow/mailer/ext/premailer/adapter/oga.rb +0 -303
- data/pakyow-mailer/lib/pakyow/mailer/helpers.rb +0 -7
- data/pakyow-mailer/lib/pakyow/mailer/mailer.rb +0 -76
- data/pakyow-mailer/lib/pakyow/mailer.rb +0 -9
- data/pakyow-mailer/lib/pakyow-mailer.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c3144870c88c7af9b1290b67d100e29e40fac2a8c64232580c3a51e702b4919f
|
4
|
+
data.tar.gz: ec24d4b029cf1968221bfcb8e97023bb14eb427b8230dfa0b964979b37ce66e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 780ff66d0c451eefd0293e08e1725886fddedbcd7cde4eeb551a0695fc9c8433f8a7c3208ecc70d929b272fd6d3b285e6ae005256da2a8b6dd3c8e84b24d3caa
|
7
|
+
data.tar.gz: 3a7251f70f859a906edb038dcd203c34d37910aa2adb32a710c71c845c8dc3f5902f64ea0e1b58c8cfc09410c1c5bae1995521babcaac41aa6427d032c882d58
|
File without changes
|
data/LICENSE
ADDED
@@ -16,8 +16,7 @@ Source code can be downloaded as part of the Pakyow project on Github:
|
|
16
16
|
|
17
17
|
# License
|
18
18
|
|
19
|
-
Pakyow Mailer is
|
20
|
-
License](http://opensource.org/licenses/MIT).
|
19
|
+
Pakyow Mailer is free and open-source under the [LGPLv3 license](https://choosealicense.com/licenses/lgpl-3.0/).
|
21
20
|
|
22
21
|
# Support
|
23
22
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/extension"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Mailer
|
7
|
+
module Behavior
|
8
|
+
module Config
|
9
|
+
extend Support::Extension
|
10
|
+
|
11
|
+
apply_extension do
|
12
|
+
configurable :mailer do
|
13
|
+
setting :default_sender, "Pakyow"
|
14
|
+
setting :default_content_type, "text/html"
|
15
|
+
setting :delivery_method, :sendmail
|
16
|
+
setting :delivery_options, {}
|
17
|
+
setting :encoding, "UTF-8"
|
18
|
+
setting :silent, true
|
19
|
+
|
20
|
+
defaults :development do
|
21
|
+
setting :silent, false
|
22
|
+
end
|
23
|
+
|
24
|
+
defaults :test do
|
25
|
+
setting :delivery_method, :test
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/framework"
|
4
|
+
|
5
|
+
require "pakyow/mailer/behavior/config"
|
6
|
+
require "pakyow/mailer/helpers"
|
7
|
+
|
8
|
+
module Pakyow
|
9
|
+
module Mailer
|
10
|
+
class Framework < Pakyow::Framework(:mailer)
|
11
|
+
def boot
|
12
|
+
object.class_eval do
|
13
|
+
include Behavior::Config
|
14
|
+
|
15
|
+
register_helper :active, Helpers
|
16
|
+
|
17
|
+
mail_renderer = Class.new(isolated(:Renderer)) do
|
18
|
+
# Override so we don't trigger any hooks.
|
19
|
+
#
|
20
|
+
def perform(output = String.new)
|
21
|
+
@presenter.to_html(output)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Delete the create_template_nodes build step since we don't want to mail templates.
|
26
|
+
#
|
27
|
+
mail_renderer.__build_fns.delete_if { |fn|
|
28
|
+
fn.source_location[0].end_with?("create_template_nodes.rb")
|
29
|
+
}
|
30
|
+
|
31
|
+
unless const_defined?(:MailRenderer, false)
|
32
|
+
const_set(:MailRenderer, mail_renderer)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
module Mailer
|
5
|
+
module Helpers
|
6
|
+
def mailer(path = nil)
|
7
|
+
if path
|
8
|
+
connection = @connection.dup
|
9
|
+
|
10
|
+
renderer = connection.app.isolated(:MailRenderer).new(
|
11
|
+
app: connection.app,
|
12
|
+
presentables: connection.values,
|
13
|
+
presenter_class: connection.app.isolated(:MailRenderer).find_presenter(connection.app, path),
|
14
|
+
composer: Presenter::Composers::View.new(path, app: @connection.app)
|
15
|
+
)
|
16
|
+
|
17
|
+
Mailer.new(
|
18
|
+
renderer: renderer,
|
19
|
+
config: app.config.mailer,
|
20
|
+
logger: connection.logger
|
21
|
+
).tap do |mailer|
|
22
|
+
if block_given?
|
23
|
+
context = dup
|
24
|
+
context.instance_variable_set(:@connection, connection)
|
25
|
+
context.instance_exec(mailer, &Proc.new)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
Mailer.new(
|
30
|
+
config: app.config.mailer,
|
31
|
+
logger: @connection.logger
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "oga"
|
4
|
+
|
5
|
+
require "pakyow/mailer/plaintext"
|
6
|
+
require "pakyow/mailer/style_inliner"
|
7
|
+
|
8
|
+
module Pakyow
|
9
|
+
module Mailer
|
10
|
+
class Mailer
|
11
|
+
def initialize(config:, renderer: nil, logger: Pakyow.logger)
|
12
|
+
@config, @renderer, @logger = config, renderer, logger
|
13
|
+
end
|
14
|
+
|
15
|
+
def deliver_to(recipient, subject: nil, sender: nil, content: nil, type: nil)
|
16
|
+
processed_content = if content
|
17
|
+
process(content, type || "text/plain")
|
18
|
+
elsif @renderer
|
19
|
+
process(@renderer.perform, @config.default_content_type)
|
20
|
+
else
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
|
24
|
+
html = processed_content[:html]
|
25
|
+
text = processed_content[:text]
|
26
|
+
|
27
|
+
mail = Mail.new
|
28
|
+
mail.from = sender || @config.default_sender
|
29
|
+
mail.content_type = type || @config.default_content_type
|
30
|
+
mail.delivery_method(@config.delivery_method, @config.delivery_options)
|
31
|
+
|
32
|
+
if html.nil?
|
33
|
+
mail.body = text
|
34
|
+
else
|
35
|
+
encoding = @config.encoding
|
36
|
+
|
37
|
+
mail.html_part do
|
38
|
+
content_type "text/html; charset=" + encoding
|
39
|
+
body html
|
40
|
+
end
|
41
|
+
|
42
|
+
mail.text_part do
|
43
|
+
content_type "text/plain; charset=" + encoding
|
44
|
+
body text
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if subject
|
49
|
+
mail.subject = subject
|
50
|
+
end
|
51
|
+
|
52
|
+
Array(recipient).map { |to|
|
53
|
+
deliverable_mail = mail.dup
|
54
|
+
deliverable_mail.to = to
|
55
|
+
deliverable_mail.deliver.tap do |delivered_mail|
|
56
|
+
unless @config.silent
|
57
|
+
log_outgoing(delivered_mail)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def process(content, content_type)
|
66
|
+
{}.tap do |processed_content|
|
67
|
+
if content_type.include?("text/html")
|
68
|
+
document = Oga.parse_html(content)
|
69
|
+
mailable_document = document.at_css("body") || document
|
70
|
+
|
71
|
+
processed_content[:text] = Plaintext.convert_to_text(
|
72
|
+
mailable_document.to_xml
|
73
|
+
)
|
74
|
+
|
75
|
+
stylesheets = if @renderer
|
76
|
+
@renderer.app.packs(@renderer.presenter.view).select(&:stylesheets?).map(&:stylesheets)
|
77
|
+
else
|
78
|
+
[]
|
79
|
+
end
|
80
|
+
|
81
|
+
processed_content[:html] = StyleInliner.new(
|
82
|
+
mailable_document,
|
83
|
+
stylesheets: stylesheets
|
84
|
+
).inlined
|
85
|
+
else
|
86
|
+
processed_content[:text] = content
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# @api private
|
92
|
+
def log_outgoing(delivered_mail)
|
93
|
+
message = String.new
|
94
|
+
message << "┌──────────────────────────────────────────────────────────────────────────────┐\n"
|
95
|
+
message << "│ Subject: #{rpad(delivered_mail.subject, -9)} │\n"
|
96
|
+
|
97
|
+
if plaintext = delivered_mail.body.parts.find { |part|
|
98
|
+
part.content_type.include?("text/plain")
|
99
|
+
}
|
100
|
+
|
101
|
+
message << "├──────────────────────────────────────────────────────────────────────────────┤\n"
|
102
|
+
|
103
|
+
plaintext.body.to_s.split("\n").each do |line|
|
104
|
+
message << "│ #{rpad(line)} │\n"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
message << "├──────────────────────────────────────────────────────────────────────────────┤\n"
|
109
|
+
message << "│ → #{rpad(delivered_mail.to.join(", "), -2)} │\n"
|
110
|
+
message << "└──────────────────────────────────────────────────────────────────────────────┘\n"
|
111
|
+
@logger.debug message
|
112
|
+
end
|
113
|
+
|
114
|
+
# @api private
|
115
|
+
def rpad(message, offset = 0)
|
116
|
+
message + " " * (76 + offset - message.length)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "htmlentities"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Mailer
|
7
|
+
module Plaintext
|
8
|
+
# Pulled from premailer (https://github.com/premailer/premailer/)
|
9
|
+
# Copyright (c) 2007-2017, Alex Dunae
|
10
|
+
|
11
|
+
# Returns the text in UTF-8 format with all HTML tags removed
|
12
|
+
#
|
13
|
+
# TODO: add support for DL, OL
|
14
|
+
def self.convert_to_text(html, line_length = 65, _from_charset = "UTF-8")
|
15
|
+
txt = html
|
16
|
+
|
17
|
+
# strip text ignored html. Useful for removing
|
18
|
+
# headers and footers that aren't needed in the
|
19
|
+
# text version
|
20
|
+
txt.gsub!(/<!-- start text\/html -->.*?<!-- end text\/html -->/m, "")
|
21
|
+
|
22
|
+
# replace images with their alt attributes
|
23
|
+
# for img tags with "" for attribute quotes
|
24
|
+
# with or without closing tag
|
25
|
+
# eg. the following formats:
|
26
|
+
# <img alt="" />
|
27
|
+
# <img alt="">
|
28
|
+
txt.gsub!(/<img.+?alt=\"([^\"]*)\"[^>]*\>/i, '\1')
|
29
|
+
|
30
|
+
# for img tags with '' for attribute quotes
|
31
|
+
# with or without closing tag
|
32
|
+
# eg. the following formats:
|
33
|
+
# <img alt='' />
|
34
|
+
# <img alt=''>
|
35
|
+
txt.gsub!(/<img.+?alt=\'([^\']*)\'[^>]*\>/i, '\1')
|
36
|
+
|
37
|
+
# links
|
38
|
+
txt.gsub!(/<a\s[^\n]*?href=["'](mailto:)?([^"']*)["'][^>]*>(.*?)<\/a>/im) do |_s|
|
39
|
+
if $3.empty?
|
40
|
+
""
|
41
|
+
elsif $3.strip.downcase == $2.strip.downcase
|
42
|
+
$3.strip
|
43
|
+
else
|
44
|
+
$3.strip + " ( " + $2.strip + " )"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# handle headings (H1-H6)
|
49
|
+
txt.gsub!(/(<\/h[1-6]>)/i, "\n\\1") # move closing tags to new lines
|
50
|
+
txt.gsub!(/[\s]*<h([1-6]+)[^>]*>[\s]*(.*)[\s]*<\/h[1-6]+>/i) do |_s|
|
51
|
+
hlevel = $1.to_i
|
52
|
+
|
53
|
+
htext = $2
|
54
|
+
htext.gsub!(/<br[\s]*\/?>/i, "\n") # handle <br>s
|
55
|
+
htext.gsub!(/<\/?[^>]*>/i, "") # strip tags
|
56
|
+
|
57
|
+
# determine maximum line length
|
58
|
+
hlength = 0
|
59
|
+
htext.each_line do |l| llength = l.strip.length; hlength = llength if llength > hlength end
|
60
|
+
hlength = line_length if hlength > line_length
|
61
|
+
|
62
|
+
case hlevel
|
63
|
+
when 1 # H1, asterisks above and below
|
64
|
+
htext = ("*" * hlength) + "\n" + htext + "\n" + ("*" * hlength)
|
65
|
+
when 2 # H1, dashes above and below
|
66
|
+
htext = ("-" * hlength) + "\n" + htext + "\n" + ("-" * hlength)
|
67
|
+
else # H3-H6, dashes below
|
68
|
+
htext = htext + "\n" + ("-" * hlength)
|
69
|
+
end
|
70
|
+
|
71
|
+
"\n\n" + htext + "\n\n"
|
72
|
+
end
|
73
|
+
|
74
|
+
# wrap spans
|
75
|
+
txt.gsub!(/(<\/span>)[\s]+(<span)/mi, '\1 \2')
|
76
|
+
|
77
|
+
# lists -- TODO: should handle ordered lists
|
78
|
+
txt.gsub!(/[\s]*(<li[^>]*>)[\s]*/i, "* ")
|
79
|
+
# list not followed by a newline
|
80
|
+
txt.gsub!(/<\/li>[\s]*(?![\n])/i, "\n")
|
81
|
+
|
82
|
+
# paragraphs and line breaks
|
83
|
+
txt.gsub!(/<\/p>/i, "\n\n")
|
84
|
+
txt.gsub!(/<br[\/ ]*>/i, "\n")
|
85
|
+
|
86
|
+
# strip remaining tags
|
87
|
+
txt.gsub!(/<\/?[^>]*>/, "")
|
88
|
+
|
89
|
+
# decode HTML entities
|
90
|
+
he = HTMLEntities.new
|
91
|
+
txt = he.decode(txt)
|
92
|
+
|
93
|
+
# word wrap
|
94
|
+
txt = word_wrap(txt, line_length)
|
95
|
+
|
96
|
+
# remove linefeeds (\r\n and \r -> \n)
|
97
|
+
txt.gsub!(/\r\n?/, "\n")
|
98
|
+
|
99
|
+
# strip extra spaces
|
100
|
+
txt.gsub!(/[ \t]*\302\240+[ \t]*/, " ") # non-breaking spaces -> spaces
|
101
|
+
txt.gsub!(/\n[ \t]+/, "\n") # space at start of lines
|
102
|
+
txt.gsub!(/[ \t]+\n/, "\n") # space at end of lines
|
103
|
+
|
104
|
+
# no more than two consecutive newlines
|
105
|
+
txt.gsub!(/[\n]{3,}/, "\n\n")
|
106
|
+
|
107
|
+
# the word messes up the parens
|
108
|
+
txt.gsub!(/\(([ \n])(http[^)]+)([\n ])\)/) do |_s|
|
109
|
+
($1 == "\n" ? $1 : "") + "( " + $2 + " )" + ($3 == "\n" ? $1 : "")
|
110
|
+
end
|
111
|
+
|
112
|
+
txt.strip
|
113
|
+
end
|
114
|
+
|
115
|
+
# Taken from Rails' word_wrap helper (http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-word_wrap)
|
116
|
+
def self.word_wrap(txt, line_length)
|
117
|
+
txt.split("\n").collect { |line|
|
118
|
+
line.length > line_length ? line.gsub(/(.{1,#{line_length}})(\s+|$)/, "\\1\n").strip : line
|
119
|
+
} * "\n"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "css_parser"
|
4
|
+
require "oga"
|
5
|
+
|
6
|
+
module Pakyow
|
7
|
+
module Mailer
|
8
|
+
# Inlines styles into html content.
|
9
|
+
#
|
10
|
+
class StyleInliner
|
11
|
+
def initialize(doc_or_html, stylesheets: [])
|
12
|
+
@css_parser = CssParser::Parser.new.tap do |parser|
|
13
|
+
stylesheets.each do |stylesheet|
|
14
|
+
parser.load_string!(stylesheet.read)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
@doc = case doc_or_html
|
19
|
+
when Oga::XML::Document
|
20
|
+
doc_or_html
|
21
|
+
when Oga::XML::Element
|
22
|
+
doc_or_html
|
23
|
+
else
|
24
|
+
Oga.parse_html(doc_or_html.to_s)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def inlined
|
29
|
+
@css_parser.each_selector(:all) do |selector, declaration|
|
30
|
+
@doc.css(selector).each do |node|
|
31
|
+
node.set(:style, [declaration, node.get(:style).to_s].join(" "))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
@doc.to_xml
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pakyow-mailer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan Powell
|
@@ -9,128 +9,171 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-07-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name: pakyow-
|
15
|
+
name: pakyow-assets
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
18
|
- - '='
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 0.
|
20
|
+
version: 1.0.0.rc1
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - '='
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 0.
|
27
|
+
version: 1.0.0.rc1
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: pakyow-core
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
32
|
- - '='
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 0.
|
34
|
+
version: 1.0.0.rc1
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - '='
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 0.
|
41
|
+
version: 1.0.0.rc1
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: pakyow-presenter
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - '='
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: 0.
|
48
|
+
version: 1.0.0.rc1
|
49
49
|
type: :runtime
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - '='
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: 0.
|
55
|
+
version: 1.0.0.rc1
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
57
|
+
name: pakyow-routing
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 1.0.0.rc1
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.0.0.rc1
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: pakyow-support
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.0.0.rc1
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 1.0.0.rc1
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: css_parser
|
58
86
|
requirement: !ruby/object:Gem::Requirement
|
59
87
|
requirements:
|
60
88
|
- - "~>"
|
61
89
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
90
|
+
version: '1.7'
|
63
91
|
type: :runtime
|
64
92
|
prerelease: false
|
65
93
|
version_requirements: !ruby/object:Gem::Requirement
|
66
94
|
requirements:
|
67
95
|
- - "~>"
|
68
96
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
97
|
+
version: '1.7'
|
70
98
|
- !ruby/object:Gem::Dependency
|
71
|
-
name:
|
99
|
+
name: htmlentities
|
72
100
|
requirement: !ruby/object:Gem::Requirement
|
73
101
|
requirements:
|
74
102
|
- - "~>"
|
75
103
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
104
|
+
version: '4.3'
|
77
105
|
type: :runtime
|
78
106
|
prerelease: false
|
79
107
|
version_requirements: !ruby/object:Gem::Requirement
|
80
108
|
requirements:
|
81
109
|
- - "~>"
|
82
110
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
111
|
+
version: '4.3'
|
84
112
|
- !ruby/object:Gem::Dependency
|
85
|
-
name:
|
113
|
+
name: mail
|
86
114
|
requirement: !ruby/object:Gem::Requirement
|
87
115
|
requirements:
|
88
116
|
- - "~>"
|
89
117
|
- !ruby/object:Gem::Version
|
90
|
-
version: '
|
91
|
-
type: :
|
118
|
+
version: '2.7'
|
119
|
+
type: :runtime
|
92
120
|
prerelease: false
|
93
121
|
version_requirements: !ruby/object:Gem::Requirement
|
94
122
|
requirements:
|
95
123
|
- - "~>"
|
96
124
|
- !ruby/object:Gem::Version
|
97
|
-
version: '
|
125
|
+
version: '2.7'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: oga
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '2.15'
|
133
|
+
type: :runtime
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '2.15'
|
98
140
|
description: Mailers for Pakyow
|
99
141
|
email: bryan@metabahn.com
|
100
142
|
executables: []
|
101
143
|
extensions: []
|
102
144
|
extra_rdoc_files: []
|
103
145
|
files:
|
104
|
-
-
|
105
|
-
-
|
106
|
-
-
|
107
|
-
-
|
108
|
-
-
|
109
|
-
-
|
110
|
-
-
|
111
|
-
-
|
112
|
-
-
|
113
|
-
|
146
|
+
- CHANGELOG.md
|
147
|
+
- LICENSE
|
148
|
+
- README.md
|
149
|
+
- lib/pakyow/mailer.rb
|
150
|
+
- lib/pakyow/mailer/behavior/config.rb
|
151
|
+
- lib/pakyow/mailer/framework.rb
|
152
|
+
- lib/pakyow/mailer/helpers.rb
|
153
|
+
- lib/pakyow/mailer/mailer.rb
|
154
|
+
- lib/pakyow/mailer/plaintext.rb
|
155
|
+
- lib/pakyow/mailer/style_inliner.rb
|
156
|
+
homepage: https://pakyow.org
|
114
157
|
licenses:
|
115
|
-
-
|
158
|
+
- LGPL-3.0
|
116
159
|
metadata: {}
|
117
160
|
post_install_message:
|
118
161
|
rdoc_options: []
|
119
162
|
require_paths:
|
120
|
-
-
|
163
|
+
- lib
|
121
164
|
required_ruby_version: !ruby/object:Gem::Requirement
|
122
165
|
requirements:
|
123
166
|
- - ">="
|
124
167
|
- !ruby/object:Gem::Version
|
125
|
-
version: 2.
|
168
|
+
version: 2.5.0
|
126
169
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
170
|
requirements:
|
128
|
-
- - "
|
171
|
+
- - ">"
|
129
172
|
- !ruby/object:Gem::Version
|
130
|
-
version:
|
173
|
+
version: 1.3.1
|
131
174
|
requirements: []
|
132
175
|
rubyforge_project:
|
133
|
-
rubygems_version: 2.
|
176
|
+
rubygems_version: 2.7.6
|
134
177
|
signing_key:
|
135
178
|
specification_version: 4
|
136
179
|
summary: Pakyow Mailer
|
data/pakyow-mailer/LICENSE
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
Copyright (c) 2011-2015 Bryan Powell
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -1,16 +0,0 @@
|
|
1
|
-
Pakyow::Config.register :mailer do |config|
|
2
|
-
# the default sender name
|
3
|
-
config.opt :default_sender, 'Pakyow'
|
4
|
-
|
5
|
-
# the default mimetype to use
|
6
|
-
config.opt :default_content_type, -> { 'text/html; charset=' + Pakyow::Config.mailer.encoding }
|
7
|
-
|
8
|
-
# the delivery method to use for sending mail
|
9
|
-
config.opt :delivery_method, :sendmail
|
10
|
-
|
11
|
-
# any delivery options necessary for `delivery_method`
|
12
|
-
config.opt :delivery_options, { enable_starttls_auto: false }
|
13
|
-
|
14
|
-
# the default encoding to use
|
15
|
-
config.opt :encoding, 'UTF-8'
|
16
|
-
end
|
@@ -1,303 +0,0 @@
|
|
1
|
-
require 'oga'
|
2
|
-
|
3
|
-
module Pakyow
|
4
|
-
class OgaAttributes
|
5
|
-
def initialize(attributes)
|
6
|
-
@attributes = attributes
|
7
|
-
end
|
8
|
-
|
9
|
-
def [](key)
|
10
|
-
if key.is_a?(Integer)
|
11
|
-
super
|
12
|
-
else
|
13
|
-
@attributes.find { |a| a.name.to_sym == key.to_sym }
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def method_missing(*args, &block)
|
18
|
-
@attributes.send(*args, &block)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
module Oga
|
24
|
-
module XML
|
25
|
-
class Document
|
26
|
-
# Premailer builds its css searches with `@` prepended to an attribute,
|
27
|
-
# which breaks Oga. Since Premailer also expects `search` to be defined
|
28
|
-
# on a document, we define it and just strip the `@` out before calling
|
29
|
-
# Oga's build-in #css method.
|
30
|
-
def search(query)
|
31
|
-
css(query.gsub('@', ''))
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class Element
|
36
|
-
def attributes
|
37
|
-
Pakyow::OgaAttributes.new(@attributes)
|
38
|
-
end
|
39
|
-
|
40
|
-
def []=(name, value)
|
41
|
-
set(name, value)
|
42
|
-
end
|
43
|
-
|
44
|
-
def [](name)
|
45
|
-
get(name)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
class Attribute
|
50
|
-
def to_str
|
51
|
-
value
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
class Premailer
|
58
|
-
# This method was tied to a specific type of document rather than being
|
59
|
-
# adapter-agnostic (honestly it's a stretch to call them adapters). So,
|
60
|
-
# we just pulled this method in and made it work w/ Oga.
|
61
|
-
def load_css_from_html! # :nodoc:
|
62
|
-
tags = @doc.css("link[rel='stylesheet']").reject { |tag|
|
63
|
-
tag.attribute('data-premailer') == 'ignore'
|
64
|
-
}
|
65
|
-
|
66
|
-
if tags
|
67
|
-
tags.each do |tag|
|
68
|
-
if tag.to_s.strip =~ /^\<link/i && tag.attribute('href') && media_type_ok?(tag.attribute('media')) && @options[:include_link_tags]
|
69
|
-
# A user might want to <link /> to a local css file that is also mirrored on the site
|
70
|
-
# but the local one is different (e.g. newer) than the live file, premailer will now choose the local file
|
71
|
-
|
72
|
-
if tag.attribute('href').to_s.include? @base_url.to_s and @html_file.kind_of?(String)
|
73
|
-
if @options[:with_html_string]
|
74
|
-
link_uri = tag.attribute('href').to_s.sub(@base_url.to_s, '')
|
75
|
-
else
|
76
|
-
link_uri = File.join(File.dirname(@html_file), tag.attribute('href').to_s.sub!(@base_url.to_s, ''))
|
77
|
-
# if the file does not exist locally, try to grab the remote reference
|
78
|
-
unless File.exists?(link_uri)
|
79
|
-
link_uri = Premailer.resolve_link(tag.attribute('href').to_s, @html_file)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
else
|
83
|
-
link_uri = tag.attribute('href').to_s
|
84
|
-
end
|
85
|
-
|
86
|
-
if Premailer.local_data?(link_uri)
|
87
|
-
$stderr.puts "Loading css from local file: " + link_uri if @options[:verbose]
|
88
|
-
load_css_from_local_file!(link_uri)
|
89
|
-
else
|
90
|
-
$stderr.puts "Loading css from uri: " + link_uri if @options[:verbose]
|
91
|
-
@css_parser.load_uri!(link_uri, {:only_media_types => [:screen, :handheld]})
|
92
|
-
end
|
93
|
-
|
94
|
-
elsif tag.to_s.strip =~ /^\<style/i && @options[:include_style_tags]
|
95
|
-
@css_parser.add_block!(tag.inner_html, :base_uri => @base_url, :base_dir => @base_dir, :only_media_types => [:screen, :handheld])
|
96
|
-
end
|
97
|
-
end
|
98
|
-
unless @options[:preserve_styles]
|
99
|
-
tags.each do |tag|
|
100
|
-
tag.remove
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
module Adapter
|
107
|
-
# Oga adapter
|
108
|
-
module Oga
|
109
|
-
|
110
|
-
# Merge CSS into the HTML document.
|
111
|
-
#
|
112
|
-
# @return [String] an HTML.
|
113
|
-
def to_inline_css
|
114
|
-
doc = @processed_doc
|
115
|
-
@unmergable_rules = CssParser::Parser.new
|
116
|
-
|
117
|
-
# Give all styles already in style attributes a specificity of 1000
|
118
|
-
# per http://www.w3.org/TR/CSS21/cascade.html#specificity
|
119
|
-
doc.css("*[style]").each do |el|
|
120
|
-
el['style'] = '[SPEC=1000[' + el.attribute('style') + ']]'
|
121
|
-
end
|
122
|
-
# Iterate through the rules and merge them into the HTML
|
123
|
-
@css_parser.each_selector(:all) do |selector, declaration, specificity, media_types|
|
124
|
-
# Save un-mergable rules separately
|
125
|
-
selector.gsub!(/:link([\s]*)+/i) { |m| $1 }
|
126
|
-
|
127
|
-
# Convert element names to lower case
|
128
|
-
selector.gsub!(/([\s]|^)([\w]+)/) { |m| $1.to_s + $2.to_s.downcase }
|
129
|
-
|
130
|
-
if Premailer.is_media_query?(media_types) || selector =~ Premailer::RE_UNMERGABLE_SELECTORS
|
131
|
-
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
|
132
|
-
else
|
133
|
-
begin
|
134
|
-
if selector =~ Premailer::RE_RESET_SELECTORS
|
135
|
-
# this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
|
136
|
-
# however, this doesn't mean for testing pur
|
137
|
-
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
|
138
|
-
end
|
139
|
-
|
140
|
-
# Change single ID CSS selectors into xpath so that we can match more
|
141
|
-
# than one element. Added to work around dodgy generated code.
|
142
|
-
selector.gsub!(/\A\#([\w_\-]+)\Z/, '*[@id=\1]')
|
143
|
-
|
144
|
-
doc.css(selector).each do |el|
|
145
|
-
if el.elem? and (el.name != 'head' and el.parent.name != 'head')
|
146
|
-
# Add a style attribute or append to the existing one
|
147
|
-
block = "[SPEC=#{specificity}[#{declaration}]]"
|
148
|
-
el['style'] = (el.attribute('style').to_s ||= '') + ' ' + block
|
149
|
-
end
|
150
|
-
end
|
151
|
-
rescue RuntimeError, ArgumentError
|
152
|
-
$stderr.puts "CSS syntax error with selector: #{selector}" if @options[:verbose]
|
153
|
-
next
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
# Remove script tags
|
159
|
-
if @options[:remove_scripts]
|
160
|
-
doc.css("script").remove
|
161
|
-
end
|
162
|
-
|
163
|
-
# Read STYLE attributes and perform folding
|
164
|
-
doc.css("*[style]").each do |el|
|
165
|
-
style = el.attribute('style').to_s
|
166
|
-
|
167
|
-
declarations = []
|
168
|
-
style.scan(/\[SPEC\=([\d]+)\[(.[^\]\]]*)\]\]/).each do |declaration|
|
169
|
-
rs = CssParser::RuleSet.new(nil, declaration[1].to_s, declaration[0].to_i)
|
170
|
-
declarations << rs
|
171
|
-
end
|
172
|
-
|
173
|
-
# Perform style folding
|
174
|
-
merged = CssParser.merge(declarations)
|
175
|
-
merged.expand_shorthand!
|
176
|
-
|
177
|
-
# Duplicate CSS attributes as HTML attributes
|
178
|
-
if Premailer::RELATED_ATTRIBUTES.has_key?(el.name) && @options[:css_to_attributes]
|
179
|
-
Premailer::RELATED_ATTRIBUTES[el.name].each do |css_att, html_att|
|
180
|
-
el[html_att] = merged[css_att].gsub(/url\(['|"](.*)['|"]\)/, '\1').gsub(/;$|\s*!important/, '').strip if el[html_att].nil? and not merged[css_att].empty?
|
181
|
-
merged.instance_variable_get("@declarations").tap do |declarations|
|
182
|
-
declarations.delete(css_att)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
# Collapse multiple rules into one as much as possible.
|
187
|
-
merged.create_shorthand! if @options[:create_shorthands]
|
188
|
-
|
189
|
-
# write the inline STYLE attribute
|
190
|
-
attributes = Premailer.escape_string(merged.declarations_to_s).split(';').map(&:strip)
|
191
|
-
attributes = attributes.map { |attr| [attr.split(':').first, attr] }.sort_by { |pair| pair.first }.map { |pair| pair[1] }
|
192
|
-
el['style'] = attributes.join('; ')
|
193
|
-
end
|
194
|
-
|
195
|
-
doc = write_unmergable_css_rules(doc, @unmergable_rules)
|
196
|
-
|
197
|
-
if @options[:remove_classes] or @options[:remove_comments]
|
198
|
-
doc.traverse do |el|
|
199
|
-
if el.comment? and @options[:remove_comments]
|
200
|
-
el.remove
|
201
|
-
elsif el.element?
|
202
|
-
el.unset('class') if @options[:remove_classes]
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
if @options[:remove_ids]
|
208
|
-
# find all anchor's targets and hash them
|
209
|
-
targets = []
|
210
|
-
doc.css("a[@href^='#']").each do |el|
|
211
|
-
target = el.get_attribute('href')[1..-1]
|
212
|
-
targets << target
|
213
|
-
el.set('href', "#" + Digest::MD5.hexdigest(target))
|
214
|
-
end
|
215
|
-
# hash ids that are links target, delete others
|
216
|
-
doc.css("*[@id]").each do |el|
|
217
|
-
id = el.get_attribute('id')
|
218
|
-
if targets.include?(id)
|
219
|
-
el.set('id', Digest::MD5.hexdigest(id))
|
220
|
-
else
|
221
|
-
el.unset('id')
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
if @options[:reset_contenteditable]
|
227
|
-
doc.css('*[contenteditable]').each do |el|
|
228
|
-
el.unset('contenteditable')
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
@processed_doc = doc
|
233
|
-
@processed_doc.to_xml
|
234
|
-
end
|
235
|
-
|
236
|
-
# Create a <tt>style</tt> element with un-mergable rules (e.g. <tt>:hover</tt>)
|
237
|
-
# and write it into the <tt>body</tt>.
|
238
|
-
#
|
239
|
-
# <tt>doc</tt> is an Oga document and <tt>unmergable_css_rules</tt> is a Css::RuleSet.
|
240
|
-
#
|
241
|
-
# @return [::Oga::XML::Document] a document.
|
242
|
-
def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc:
|
243
|
-
styles = unmergable_rules.to_s
|
244
|
-
|
245
|
-
unless styles.empty?
|
246
|
-
style_tag = "<style type=\"text/css\">\n#{styles}</style>"
|
247
|
-
unless (body = doc.css('body')).empty?
|
248
|
-
if doc.at_css('body').children && !doc.at_css('body').children.empty?
|
249
|
-
doc.at_css('body').children.before(::Oga.parse_html(style_tag))
|
250
|
-
else
|
251
|
-
doc.at_css('body').add_child(::Oga.parse_html(style_tag))
|
252
|
-
end
|
253
|
-
else
|
254
|
-
doc.inner_html = style_tag += doc.inner_html
|
255
|
-
end
|
256
|
-
end
|
257
|
-
doc
|
258
|
-
end
|
259
|
-
|
260
|
-
|
261
|
-
# Converts the HTML document to a format suitable for plain-text e-mail.
|
262
|
-
#
|
263
|
-
# If present, uses the <body> element as its base; otherwise uses the whole document.
|
264
|
-
#
|
265
|
-
# @return [String] a plain text.
|
266
|
-
def to_plain_text
|
267
|
-
html_src = ''
|
268
|
-
begin
|
269
|
-
html_src = @doc.at("body").inner_html
|
270
|
-
rescue;
|
271
|
-
end
|
272
|
-
|
273
|
-
html_src = @doc.to_xml unless html_src and not html_src.empty?
|
274
|
-
convert_to_text(html_src, @options[:line_length], @html_encoding)
|
275
|
-
end
|
276
|
-
|
277
|
-
# Gets the original HTML as a string.
|
278
|
-
# @return [String] HTML.
|
279
|
-
def to_s
|
280
|
-
@doc.to_xml
|
281
|
-
end
|
282
|
-
|
283
|
-
# Load the HTML file and convert it into an Oga document.
|
284
|
-
#
|
285
|
-
# @return [::Oga::XML::Document] a document.
|
286
|
-
def load_html(input) # :nodoc:
|
287
|
-
thing = nil
|
288
|
-
|
289
|
-
# TODO: duplicate options
|
290
|
-
if @options[:with_html_string] or @options[:inline] or input.respond_to?(:read)
|
291
|
-
thing = input
|
292
|
-
elsif @is_local_file
|
293
|
-
@base_dir = File.dirname(input)
|
294
|
-
thing = File.open(input, 'r')
|
295
|
-
else
|
296
|
-
thing = open(input)
|
297
|
-
end
|
298
|
-
|
299
|
-
::Oga.parse_html(thing)
|
300
|
-
end
|
301
|
-
end
|
302
|
-
end
|
303
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
class Mailer
|
3
|
-
attr_accessor :view, :message, :processed
|
4
|
-
|
5
|
-
def self.from_store(view_path, view_store, context = nil)
|
6
|
-
view = view_store.view(view_path)
|
7
|
-
new(view: Pakyow::Presenter::ViewContext.new(view, context))
|
8
|
-
end
|
9
|
-
|
10
|
-
def initialize(view: nil, content: nil)
|
11
|
-
@view = view
|
12
|
-
@content = content
|
13
|
-
|
14
|
-
@message = Mail.new
|
15
|
-
@message.from = Config.mailer.default_sender
|
16
|
-
@message.content_type = Config.mailer.default_content_type
|
17
|
-
@message.delivery_method(Config.mailer.delivery_method, Config.mailer.delivery_options)
|
18
|
-
end
|
19
|
-
|
20
|
-
def deliver_to(recipient, subject = nil)
|
21
|
-
html = content :html
|
22
|
-
text = content :text
|
23
|
-
|
24
|
-
if html.nil?
|
25
|
-
@message.body = text
|
26
|
-
else
|
27
|
-
@message.html_part do
|
28
|
-
content_type 'text/html; charset=' + Config.mailer.encoding
|
29
|
-
body html
|
30
|
-
end
|
31
|
-
|
32
|
-
@message.text_part do
|
33
|
-
body text
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
@message.subject = subject if subject
|
38
|
-
|
39
|
-
Array(recipient).each {|r| deliver(r)}
|
40
|
-
end
|
41
|
-
|
42
|
-
def content(type = :html)
|
43
|
-
return process.fetch(type, nil)
|
44
|
-
end
|
45
|
-
|
46
|
-
protected
|
47
|
-
|
48
|
-
def process
|
49
|
-
unless @processed
|
50
|
-
@processed_content = {}
|
51
|
-
|
52
|
-
if @view
|
53
|
-
@premailer = Premailer.new(view.to_html, with_html_string: true, input_encoding: Config.mailer.encoding)
|
54
|
-
|
55
|
-
@premailer.warnings.each do |w|
|
56
|
-
Pakyow.logger.warn "#{w[:message]} (#{w[:level]}) may not render properly in #{w[:clients]}"
|
57
|
-
end
|
58
|
-
|
59
|
-
@processed_content[:text] = @content || @premailer.to_plain_text
|
60
|
-
@processed_content[:html] = @premailer.to_inline_css
|
61
|
-
else
|
62
|
-
@processed_content[:text] = @content
|
63
|
-
end
|
64
|
-
|
65
|
-
@processed = true
|
66
|
-
end
|
67
|
-
|
68
|
-
return @processed_content
|
69
|
-
end
|
70
|
-
|
71
|
-
def deliver(recipient)
|
72
|
-
@message.to = recipient
|
73
|
-
@message.deliver
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1 +0,0 @@
|
|
1
|
-
require 'pakyow/mailer'
|