pakyow-mailer 0.11.3 → 1.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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'
|