html2email 0.1.2
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.
- data/.gitignore +1 -0
- data/LICENSE +23 -0
- data/README.markdown +110 -0
- data/Rakefile +57 -0
- data/bin/html2email +5 -0
- data/html2email.gemspec +47 -0
- data/lib/html2email/context.rb +42 -0
- data/lib/html2email/html_email.rb +59 -0
- data/lib/html2email/html_mailer.rb +49 -0
- data/lib/html2email/vendor/premailer/.gitignore +1 -0
- data/lib/html2email/vendor/premailer/CHANGELOG.rdoc +62 -0
- data/lib/html2email/vendor/premailer/LICENSE.rdoc +42 -0
- data/lib/html2email/vendor/premailer/README.rdoc +66 -0
- data/lib/html2email/vendor/premailer/bin/premailer +72 -0
- data/lib/html2email/vendor/premailer/bin/trollop.rb +739 -0
- data/lib/html2email/vendor/premailer/init.rb +1 -0
- data/lib/html2email/vendor/premailer/lib/premailer/html_to_plain_text.rb +81 -0
- data/lib/html2email/vendor/premailer/lib/premailer/premailer.rb +464 -0
- data/lib/html2email/vendor/premailer/lib/premailer.rb +9 -0
- data/lib/html2email/vendor/premailer/misc/client_support.yaml +230 -0
- data/lib/html2email/vendor/premailer/premailer.gemspec +20 -0
- data/lib/html2email/vendor/premailer/rakefile.rb +42 -0
- data/lib/html2email/vendor/premailer/tests/files/base.html +145 -0
- data/lib/html2email/vendor/premailer/tests/files/contact_bg.png +0 -0
- data/lib/html2email/vendor/premailer/tests/files/dialect.png +0 -0
- data/lib/html2email/vendor/premailer/tests/files/dots_end.png +0 -0
- data/lib/html2email/vendor/premailer/tests/files/dots_h.gif +0 -0
- data/lib/html2email/vendor/premailer/tests/files/import.css +13 -0
- data/lib/html2email/vendor/premailer/tests/files/inc/2009-placeholder.png +0 -0
- data/lib/html2email/vendor/premailer/tests/files/noimport.css +13 -0
- data/lib/html2email/vendor/premailer/tests/files/styles.css +102 -0
- data/lib/html2email/vendor/premailer/tests/test_helper.rb +2 -0
- data/lib/html2email/vendor/premailer/tests/test_html_to_plain_text.rb +73 -0
- data/lib/html2email/vendor/premailer/tests/test_link_resolver.rb +49 -0
- data/lib/html2email/vendor/premailer/tests/test_premailer.rb +124 -0
- data/lib/html2email.rb +110 -0
- data/spec/html2email.spec.rb +9 -0
- metadata +176 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg/
|
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Html2Email: Tilt + Premailer + SMTP
|
2
|
+
http://github.com/guns/html2email
|
3
|
+
Copyright (c) 2010 Sung Pae <sung@metablu.com>
|
4
|
+
|
5
|
+
Published under the MIT License:
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
9
|
+
in the Software without restriction, including without limitation the rights
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
12
|
+
furnished to do so, subject to the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included in
|
15
|
+
all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
+
THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
Html2Email: Tilt + Premailer + SMTP
|
2
|
+
===================================
|
3
|
+
|
4
|
+
Making rich HTML emails is a pain. You throw away everything you know about
|
5
|
+
semantic markup, CSS, and keeping things DRY, and memorize a large heap of
|
6
|
+
senseless special cases for displaying correctly across at __least__ 30
|
7
|
+
combinations of email clients, operating systems, browsers, and online email
|
8
|
+
services; and even then, it's still not going to look right in Outlook 2007.
|
9
|
+
|
10
|
+
It's a strange game. The only winning move is not to play.
|
11
|
+
|
12
|
+
If you have to play though, you should have a workflow:
|
13
|
+
|
14
|
+
* Use your favorite templating engine: use any engine supported by [Tilt][]
|
15
|
+
* Don't abandon stylesheets: [Premailer][] inlines external styles for you
|
16
|
+
* Use a layout file for similar projects
|
17
|
+
* Override information in the layout per email
|
18
|
+
* Email previews to a list of test addresses right from the command line
|
19
|
+
|
20
|
+
Before you start, be sure to understand what you're getting into so that you
|
21
|
+
don't lose too much hair over your project:
|
22
|
+
|
23
|
+
<http://www.campaignmonitor.com/design-guidelines/>
|
24
|
+
|
25
|
+
Synopsis
|
26
|
+
--------
|
27
|
+
|
28
|
+
Command line, render email template with layout:
|
29
|
+
|
30
|
+
$ html2email --layout layout.haml client/offer.erb
|
31
|
+
# => Creates client/offer.html
|
32
|
+
|
33
|
+
Command line, pipe text into `html2email` with layout, get text back on STDOUT:
|
34
|
+
|
35
|
+
$ curl example.com/offer.html | html2email -l layout.haml > offer.html
|
36
|
+
|
37
|
+
Command line, send test email after render:
|
38
|
+
|
39
|
+
html2email -l layout.haml --email sung@metablu.com client/offer.erb
|
40
|
+
|
41
|
+
In the layout file, layout.haml. Note that linked stylesheets can be CSS,
|
42
|
+
[Sass][], or [LESS][]:
|
43
|
+
|
44
|
+
- @client_name = 'Example Inc.'
|
45
|
+
%html
|
46
|
+
%head
|
47
|
+
%title&= @page_title || 'A generic title'
|
48
|
+
%link{ :rel => 'stylesheet', :href => 'layout.sass',
|
49
|
+
:type => 'text/css', :media => 'screen' }
|
50
|
+
%body
|
51
|
+
= yield
|
52
|
+
|
53
|
+
In the email template, offer.erb. The `:prebinding` method takes a block which
|
54
|
+
makes available to both the layout and the template the variables created
|
55
|
+
in the block. It should ideally be declared at the top of the template file:
|
56
|
+
|
57
|
+
<% prebinding do %>
|
58
|
+
<% @page_title = 'An example offer!' %>
|
59
|
+
<% end %>
|
60
|
+
<table>
|
61
|
+
<tr>
|
62
|
+
<td>Hello, <%= @client_name %></td>
|
63
|
+
</tr>
|
64
|
+
</table>
|
65
|
+
|
66
|
+
Ruby interface:
|
67
|
+
|
68
|
+
require 'html2email/html_email'
|
69
|
+
|
70
|
+
html = HtmlEmail.new('client/offer.erb', 'layout.haml').render
|
71
|
+
File.open('client/offer.html', 'w') { |f| f.write html }
|
72
|
+
|
73
|
+
NOTE
|
74
|
+
----
|
75
|
+
|
76
|
+
Html2Email was put together very quickly to address a personal need. Most of the
|
77
|
+
work is done by [Tilt][] and [Premailer][], so it works just fine, but it lacks
|
78
|
+
tests and polish. Those are forthcoming.
|
79
|
+
|
80
|
+
Premailer is forked and vendored in `lib/html2email/vendor/premailer/`
|
81
|
+
|
82
|
+
Html2Email is not an email sending engine! It is only meant to ease the
|
83
|
+
development of HTML emails. You should be using a service like
|
84
|
+
[Campaign Monitor][] or [MailChimp][] to actually send bulk emails.
|
85
|
+
|
86
|
+
TODO
|
87
|
+
----
|
88
|
+
|
89
|
+
* Live mode (auto-compile with webrick server)
|
90
|
+
* Partials
|
91
|
+
* Tests
|
92
|
+
* Create <td width='\d+'> attributes in Premailer
|
93
|
+
* Mail configuration (external SMTP servers)
|
94
|
+
* Automatic conversion and upload of relative image links to a host via ssh/ftp?
|
95
|
+
* Maybe import ActionView or Sinatra::Helpers?
|
96
|
+
|
97
|
+
LICENSE
|
98
|
+
-------
|
99
|
+
|
100
|
+
http://github.com/guns/html2email
|
101
|
+
Copyright (c) 2010 Sung Pae <sung@metablu.com>
|
102
|
+
Distributed under the MIT license.
|
103
|
+
http://www.opensource.org/licenses/mit-license.php
|
104
|
+
|
105
|
+
[Tilt]: http://github.com/rtomayko/tilt
|
106
|
+
[Premailer]: http://github.com/alexdunae/premailer/
|
107
|
+
[Campaign Monitor]: http://www.campaignmonitor.com/
|
108
|
+
[MailChimp]: http://www.mailchimp.com/
|
109
|
+
[Sass]: http://sass-lang.com/
|
110
|
+
[LESS]: http://lesscss.org/
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec/rake/spectask'
|
2
|
+
require File.expand_path '../lib/html2email', __FILE__
|
3
|
+
|
4
|
+
### Helpers
|
5
|
+
|
6
|
+
verbose false
|
7
|
+
|
8
|
+
def gemspec
|
9
|
+
Gem::Specification.new do |gem|
|
10
|
+
gem.name = (@name = 'html2email')
|
11
|
+
gem.version = Html2Email::VERSION
|
12
|
+
gem.author = 'guns'
|
13
|
+
gem.email = 'sung@metablu.com'
|
14
|
+
gem.homepage = 'http://github.com/guns/html2email'
|
15
|
+
gem.summary = 'Html2Email: Tilt + Premailer + SMTP'
|
16
|
+
gem.description = 'Convert ruby html templates to an email compatible form.'
|
17
|
+
gem.executables = ['html2email']
|
18
|
+
gem.files = %x{git ls-files}.split("\n").reject { |f| f[/vendor/] } +
|
19
|
+
%x{cd #{base = 'lib/html2email/vendor/premailer'}; git ls-files}
|
20
|
+
.split("\n").map { |f| "#{base}/#{f}" }
|
21
|
+
gem.add_dependency 'rack'
|
22
|
+
gem.add_dependency 'tilt'
|
23
|
+
# Premailer
|
24
|
+
gem.add_dependency 'hpricot', '>= 0.6'
|
25
|
+
gem.add_dependency 'css_parser', '>= 0.9.1'
|
26
|
+
gem.add_dependency 'text-reform', '>= 0.2.0'
|
27
|
+
gem.add_dependency 'htmlentities', '>= 4.0.0'
|
28
|
+
# gem.add_development_dependency 'rspec'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
### Tasks
|
33
|
+
|
34
|
+
task :default => :build
|
35
|
+
|
36
|
+
desc 'Run unit tests'
|
37
|
+
Spec::Rake::SpecTask.new :spec do |t|
|
38
|
+
t.spec_files = FileList['spec/**/*.spec.rb']
|
39
|
+
t.spec_opts = %w[--color --format=progress --debugger]
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'Write gemspec and build gem'
|
43
|
+
task :build => :spec do
|
44
|
+
if (spec = gemspec).respond_to? :to_ruby
|
45
|
+
puts "### New gemspec: #{specfile = "#{@name}.gemspec"}"
|
46
|
+
File.open(specfile, 'w') { |f| f.write(spec.to_ruby) }
|
47
|
+
end
|
48
|
+
gemfile = Gem::Builder.new(spec) { |pkg| pkg.need_tar = true }.build
|
49
|
+
puts "### New gem: #{gemfile}"
|
50
|
+
mkdir_p 'pkg'; mv gemfile, (@gem = "pkg/#{@gemfile}")
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'Install gem'
|
54
|
+
task :install => :build do
|
55
|
+
puts "### Installing #{@gem}:"
|
56
|
+
system 'gem', 'install', @gem
|
57
|
+
end
|
data/bin/html2email
ADDED
data/html2email.gemspec
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{html2email}
|
5
|
+
s.version = "0.1.2"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["guns"]
|
9
|
+
s.date = %q{2010-05-24}
|
10
|
+
s.default_executable = %q{html2email}
|
11
|
+
s.description = %q{Convert ruby html templates to an email compatible form.}
|
12
|
+
s.email = %q{sung@metablu.com}
|
13
|
+
s.executables = ["html2email"]
|
14
|
+
s.files = [".gitignore", "LICENSE", "README.markdown", "Rakefile", "bin/html2email", "html2email.gemspec", "lib/html2email.rb", "lib/html2email/context.rb", "lib/html2email/html_email.rb", "lib/html2email/html_mailer.rb", "spec/html2email.spec.rb", "lib/html2email/vendor/premailer/.gitignore", "lib/html2email/vendor/premailer/CHANGELOG.rdoc", "lib/html2email/vendor/premailer/LICENSE.rdoc", "lib/html2email/vendor/premailer/README.rdoc", "lib/html2email/vendor/premailer/bin/premailer", "lib/html2email/vendor/premailer/bin/trollop.rb", "lib/html2email/vendor/premailer/init.rb", "lib/html2email/vendor/premailer/lib/premailer.rb", "lib/html2email/vendor/premailer/lib/premailer/html_to_plain_text.rb", "lib/html2email/vendor/premailer/lib/premailer/premailer.rb", "lib/html2email/vendor/premailer/misc/client_support.yaml", "lib/html2email/vendor/premailer/premailer.gemspec", "lib/html2email/vendor/premailer/rakefile.rb", "lib/html2email/vendor/premailer/tests/files/base.html", "lib/html2email/vendor/premailer/tests/files/contact_bg.png", "lib/html2email/vendor/premailer/tests/files/dialect.png", "lib/html2email/vendor/premailer/tests/files/dots_end.png", "lib/html2email/vendor/premailer/tests/files/dots_h.gif", "lib/html2email/vendor/premailer/tests/files/import.css", "lib/html2email/vendor/premailer/tests/files/inc/2009-placeholder.png", "lib/html2email/vendor/premailer/tests/files/noimport.css", "lib/html2email/vendor/premailer/tests/files/styles.css", "lib/html2email/vendor/premailer/tests/test_helper.rb", "lib/html2email/vendor/premailer/tests/test_html_to_plain_text.rb", "lib/html2email/vendor/premailer/tests/test_link_resolver.rb", "lib/html2email/vendor/premailer/tests/test_premailer.rb"]
|
15
|
+
s.homepage = %q{http://github.com/guns/html2email}
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubygems_version = %q{1.3.6}
|
18
|
+
s.summary = %q{Html2Email: Tilt + Premailer + SMTP}
|
19
|
+
|
20
|
+
if s.respond_to? :specification_version then
|
21
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
22
|
+
s.specification_version = 3
|
23
|
+
|
24
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
25
|
+
s.add_runtime_dependency(%q<rack>, [">= 0"])
|
26
|
+
s.add_runtime_dependency(%q<tilt>, [">= 0"])
|
27
|
+
s.add_runtime_dependency(%q<hpricot>, [">= 0.6"])
|
28
|
+
s.add_runtime_dependency(%q<css_parser>, [">= 0.9.1"])
|
29
|
+
s.add_runtime_dependency(%q<text-reform>, [">= 0.2.0"])
|
30
|
+
s.add_runtime_dependency(%q<htmlentities>, [">= 4.0.0"])
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<rack>, [">= 0"])
|
33
|
+
s.add_dependency(%q<tilt>, [">= 0"])
|
34
|
+
s.add_dependency(%q<hpricot>, [">= 0.6"])
|
35
|
+
s.add_dependency(%q<css_parser>, [">= 0.9.1"])
|
36
|
+
s.add_dependency(%q<text-reform>, [">= 0.2.0"])
|
37
|
+
s.add_dependency(%q<htmlentities>, [">= 4.0.0"])
|
38
|
+
end
|
39
|
+
else
|
40
|
+
s.add_dependency(%q<rack>, [">= 0"])
|
41
|
+
s.add_dependency(%q<tilt>, [">= 0"])
|
42
|
+
s.add_dependency(%q<hpricot>, [">= 0.6"])
|
43
|
+
s.add_dependency(%q<css_parser>, [">= 0.9.1"])
|
44
|
+
s.add_dependency(%q<text-reform>, [">= 0.2.0"])
|
45
|
+
s.add_dependency(%q<htmlentities>, [">= 4.0.0"])
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Templates are evaluated in the scope of Context.new
|
5
|
+
#
|
6
|
+
class Context
|
7
|
+
include Rack::Utils
|
8
|
+
alias_method :h, :escape_html
|
9
|
+
|
10
|
+
class PrebindingException < Exception; end
|
11
|
+
|
12
|
+
class Attr < Hash
|
13
|
+
def to_s
|
14
|
+
self.map { |k,v|
|
15
|
+
"#{Rack::Utils.escape_html k}='#{Rack::Utils.escape_html v}'"
|
16
|
+
}.join(' ')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@binding, @test_recipients = nil, []
|
22
|
+
end
|
23
|
+
|
24
|
+
def prebinding(&block)
|
25
|
+
return if @binding
|
26
|
+
@binding = (block.call; binding)
|
27
|
+
raise PrebindingException
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :test_recipients
|
31
|
+
def add_test_recipients(*list)
|
32
|
+
@test_recipients += list.flatten
|
33
|
+
end
|
34
|
+
|
35
|
+
def link_to(text, url, opts = {})
|
36
|
+
%Q(<a href='#{h url}' target='_blank' #{Attr[opts]}>#{text}</a>)
|
37
|
+
end
|
38
|
+
|
39
|
+
def image_tag(src, opts = {})
|
40
|
+
%Q(<img src='#{h src}' #{Attr[opts]} />)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'tilt'
|
3
|
+
require 'html2email/context'
|
4
|
+
require 'html2email/vendor/premailer/lib/premailer'
|
5
|
+
|
6
|
+
class HtmlEmail
|
7
|
+
def initialize(template, layout = nil, options = {})
|
8
|
+
@template, @layout, @options = template, layout, options
|
9
|
+
@options[:default_type] ||= 'str'
|
10
|
+
@context = Context.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# returns converted html string
|
14
|
+
def render
|
15
|
+
buf = if @layout
|
16
|
+
# run through template once to catch prebinding block
|
17
|
+
begin
|
18
|
+
tilt_render @template
|
19
|
+
rescue Context::PrebindingException
|
20
|
+
rescue
|
21
|
+
# some other StandardError was raised, probably a NameError;
|
22
|
+
# reset the context to minimize the leaky abstraction
|
23
|
+
@context = Context.new
|
24
|
+
end
|
25
|
+
# return the full render with the new lexical binding
|
26
|
+
tilt_render(@layout) { tilt_render @template }
|
27
|
+
else
|
28
|
+
tilt_render @template
|
29
|
+
end
|
30
|
+
inline_css buf
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_recipients
|
34
|
+
@context.test_recipients
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def tilt_render(file)
|
40
|
+
klass = Tilt[file] || Tilt.mappings[@options[:default_type]]
|
41
|
+
klass.new(file).render(@context) { yield if block_given? }
|
42
|
+
end
|
43
|
+
|
44
|
+
# use Premailer to embed styles
|
45
|
+
def inline_css(html)
|
46
|
+
# Premailer only works on files, hence the tempfile
|
47
|
+
base = File.expand_path File.dirname(@layout || @template)
|
48
|
+
# any relative links are resolved by Premailer relative to the filepath
|
49
|
+
Tempfile.open(self.class.to_s, base) do |tmp|
|
50
|
+
tmp.write html; tmp.rewind
|
51
|
+
pre = Premailer.new tmp.path, :warn_level => Premailer::Warnings::RISKY
|
52
|
+
pre.warnings.each do |w|
|
53
|
+
warn "#{w[:message]} (#{w[:level]}) " +
|
54
|
+
"may not render properly in #{w[:clients]}"
|
55
|
+
end
|
56
|
+
pre.to_inline_css
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
|
3
|
+
class HtmlMailer
|
4
|
+
MAX_RECIPIENTS = 10
|
5
|
+
|
6
|
+
attr_reader :from_addr
|
7
|
+
|
8
|
+
def initialize(messages, list, options = {})
|
9
|
+
@messages, @list = messages, list
|
10
|
+
@from_addr = options[:from_addr] ||
|
11
|
+
"do-not-reply@#{ENV['HOSTNAME'] || 'localhost'}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def html_send
|
15
|
+
check_recipients @list
|
16
|
+
|
17
|
+
Net::SMTP.start 'localhost' do |smtp|
|
18
|
+
@messages.each do |html|
|
19
|
+
smtp.send_message header(page_title(html)) + html, from_addr, @list
|
20
|
+
end
|
21
|
+
end
|
22
|
+
# user may not have a local mail server; let them down gentle
|
23
|
+
rescue Errno::ECONNREFUSED
|
24
|
+
warn '# Connection to localhost:25 refused! Is your mailserver running?'
|
25
|
+
end
|
26
|
+
|
27
|
+
def header(title)
|
28
|
+
%{From: Html2Email <#{from_addr}>
|
29
|
+
MIME-Version: 1.0
|
30
|
+
Content-type: text/html
|
31
|
+
Subject: Html2Email test#{": #{title}" if title && !title.empty?}\n
|
32
|
+
}.gsub(/^ +/,'')
|
33
|
+
end
|
34
|
+
|
35
|
+
def page_title(html)
|
36
|
+
html[/<head.*?>.*?<title.*?>(.*?)<\/title>/m, 1]
|
37
|
+
end
|
38
|
+
|
39
|
+
def check_recipients(list)
|
40
|
+
if list.empty?
|
41
|
+
raise '# No recipients defined for email test!'
|
42
|
+
elsif list.size > MAX_RECIPIENTS
|
43
|
+
raise "# Too many recipients defined! You shouldn't need any more than " +
|
44
|
+
MAX_RECIPIENTS.to_s
|
45
|
+
else
|
46
|
+
warn "# Sending test to #{list.join ', '}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
.DS_Store
|
@@ -0,0 +1,62 @@
|
|
1
|
+
= Premailer CHANGELOG
|
2
|
+
|
3
|
+
== Version 1.6.0
|
4
|
+
* --css option for specifying additional stylesheets
|
5
|
+
* copy related CSS attributes to HTML (inspired by http://github.com/peterbe/premailer/commit/c4f2634a99fc5005011ffde54ae0336ea1497ef5)
|
6
|
+
* ignore spaces around links in HREFs
|
7
|
+
|
8
|
+
== Version 1.5.4
|
9
|
+
* new bin/premailer script
|
10
|
+
* added missing htmlentities depenency to gemspec (thanks to http://github.com/usefulthink )
|
11
|
+
* fixed handling of unspecified <link> media types
|
12
|
+
|
13
|
+
== Version 1.5.3
|
14
|
+
* improved plaintext conversion
|
15
|
+
|
16
|
+
== Version 1.5.2
|
17
|
+
* released to GitHub
|
18
|
+
* fixed handling of mailto links
|
19
|
+
* various minor updates
|
20
|
+
|
21
|
+
== Version 1.5.1
|
22
|
+
* bugfix (http://code.google.com/p/premailer/issues/detail?id=1 and http://code.google.com/p/premailer/issues/detail?id=2) thanks to Russell Norris
|
23
|
+
* bugfix (http://code.google.com/p/premailer/issues/detail?id=4) thanks to Dave Holmes
|
24
|
+
|
25
|
+
== Version 1.5.0
|
26
|
+
* preview release of Ruby gem
|
27
|
+
|
28
|
+
== Version 1.4
|
29
|
+
* incremental parsing improvements
|
30
|
+
* respect <tt>@media</tt> rule (http://www.w3.org/TR/CSS21/media.html#at-media-rule)
|
31
|
+
* better quote escaping
|
32
|
+
|
33
|
+
== Version 1.3
|
34
|
+
* separate CSS parser into its own library
|
35
|
+
* handle <tt>background: red url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR42mP4%2F58BAAT%2FAf9jgNErAAAAAElFTkSuQmCC);</tt>
|
36
|
+
* preserve <tt>:hover</tt> etc... in head styles
|
37
|
+
|
38
|
+
== Version 1.2
|
39
|
+
* respect <tt>LINK</tt> media types
|
40
|
+
* better style folding
|
41
|
+
* incremental parsing improvements
|
42
|
+
|
43
|
+
== Version 1.1
|
44
|
+
* proper calculation of selector specificity per CSS 2.1 spec
|
45
|
+
* support for <tt>@import</tt>
|
46
|
+
* preliminary support for shorthand CSS properties (<tt>margin</tt>, <tt>padding</tt>)
|
47
|
+
* preliminary separation of CSS parser
|
48
|
+
|
49
|
+
== Version 1.0
|
50
|
+
* ported web interface to eRuby
|
51
|
+
* incremental parsing improvements
|
52
|
+
|
53
|
+
== Version 0.9
|
54
|
+
* initial proof-of-concept
|
55
|
+
* PHP web version
|
56
|
+
|
57
|
+
== TODO: Future
|
58
|
+
* complete shorthand properties support (<tt>border-width</tt>, <tt>font</tt>, <tt>background</tt>)
|
59
|
+
* UTF-8 and other charsets (test page: http://kianga.kcore.de/2004/09/21/utf8_test)
|
60
|
+
* make warnings for <tt>border</tt> match <tt>border-left</tt>, etc...
|
61
|
+
* Integrate CSS validator
|
62
|
+
* Remove unused classes and IDs
|
@@ -0,0 +1,42 @@
|
|
1
|
+
= Premailer License
|
2
|
+
|
3
|
+
Copyright (c) 2007-09 Alex Dunae
|
4
|
+
|
5
|
+
Premailer is copyrighted free software by Alex Dunae (http://dunae.ca/).
|
6
|
+
You can redistribute it and/or modify it under the conditions below:
|
7
|
+
|
8
|
+
1. You may make and give away verbatim copies of the source form of the
|
9
|
+
software without restriction, provided that you duplicate all of the
|
10
|
+
original copyright notices and associated disclaimers.
|
11
|
+
|
12
|
+
2. You may modify your copy of the software in any way, provided that
|
13
|
+
you do at least ONE of the following:
|
14
|
+
|
15
|
+
a) place your modifications in the Public Domain or otherwise
|
16
|
+
make them Freely Available, such as by posting said
|
17
|
+
modifications to the internet or an equivalent medium, or by
|
18
|
+
allowing the author to include your modifications in the software.
|
19
|
+
|
20
|
+
b) use the modified software only within your corporation or
|
21
|
+
organization.
|
22
|
+
|
23
|
+
c) rename any non-standard executables so the names do not conflict
|
24
|
+
with standard executables, which must also be provided.
|
25
|
+
|
26
|
+
d) make other distribution arrangements with the author.
|
27
|
+
|
28
|
+
3. You may modify and include the part of the software into any other
|
29
|
+
software (possibly commercial) as long as clear acknowledgement and
|
30
|
+
a link back to the original software (http://code.dunae.ca/premailer.web/)
|
31
|
+
is provided.
|
32
|
+
|
33
|
+
5. The scripts and library files supplied as input to or produced as
|
34
|
+
output from the software do not automatically fall under the
|
35
|
+
copyright of the software, but belong to whomever generated them,
|
36
|
+
and may be sold commercially, and may be aggregated with this
|
37
|
+
software.
|
38
|
+
|
39
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
40
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
41
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
42
|
+
PURPOSE.
|
@@ -0,0 +1,66 @@
|
|
1
|
+
= Premailer README
|
2
|
+
|
3
|
+
=== What is this?
|
4
|
+
|
5
|
+
For the best HTML e-mail delivery results, CSS should be inline. This is a
|
6
|
+
huge pain and a simple newsletter becomes un-managable very quickly. This
|
7
|
+
script is my solution.
|
8
|
+
|
9
|
+
* CSS styles are converted to inline style attributes
|
10
|
+
Checks <tt>style</tt> and <tt>link[rel=stylesheet]</tt> tags and preserves existing inline attributes
|
11
|
+
* Relative paths are converted to absolute paths
|
12
|
+
Checks links in <tt>href</tt>, <tt>src</tt> and CSS <tt>url('')</tt>
|
13
|
+
* CSS properties are checked against e-mail client capabilities
|
14
|
+
Based on the Email Standards Project's guides
|
15
|
+
* A plain text version is created
|
16
|
+
Optional
|
17
|
+
|
18
|
+
|
19
|
+
=== Installation
|
20
|
+
|
21
|
+
Download the Premailer gem from GemCutter.
|
22
|
+
|
23
|
+
gem sources -a http://gemcutter.org
|
24
|
+
sudo gem install premailer
|
25
|
+
|
26
|
+
=== Example
|
27
|
+
premailer = Premailer.new('http://example.com/myfile.html', :warn_level => Premailer::Warnings::SAFE)
|
28
|
+
|
29
|
+
# Write the HTML output
|
30
|
+
fout = File.open("output.html", "w")
|
31
|
+
fout.puts premailer.to_inline_css
|
32
|
+
fout.close
|
33
|
+
|
34
|
+
# Write the plain-text output
|
35
|
+
fout = File.open("ouput.txt", "w")
|
36
|
+
fout.puts premailer.to_plain_text
|
37
|
+
fout.close
|
38
|
+
|
39
|
+
# Output any CSS warnings
|
40
|
+
premailer.warnings.each do |w|
|
41
|
+
puts "#{w[:message]} (#{w[:level]}) may not render properly in #{w[:clients]}"
|
42
|
+
end
|
43
|
+
|
44
|
+
=== Contributions
|
45
|
+
|
46
|
+
Contributions are most welcome. Premailer was rotting away in a private SVN repository for too long and could use some TLC. Pull and patch to your heart's content.
|
47
|
+
|
48
|
+
A few areas that are particularly in need of love:
|
49
|
+
* Testing suite
|
50
|
+
There were unit tests but they were so funky that it was better to just strip them out.
|
51
|
+
* Test running Premailer on local files
|
52
|
+
* Create a binary file for easing command line use, allowing the output to be piped in *nix systems
|
53
|
+
* Ruby 1.9 testing
|
54
|
+
* Test with Rails
|
55
|
+
* Move un-repeated background images defined in CSS to <tt><td background=""></tt> for Outlook
|
56
|
+
* Correctly parse http://www.webstandards.org/files/acid2/test.html
|
57
|
+
|
58
|
+
=== Credits and code
|
59
|
+
|
60
|
+
Premailer is written in Ruby.
|
61
|
+
|
62
|
+
The web interface can be found at http://premailer.dialect.ca .
|
63
|
+
|
64
|
+
The source code can be found at http://github.com/alexdunae/premailer .
|
65
|
+
|
66
|
+
Written by Alex Dunae (dunae.ca, e-mail 'code' at the same domain), 2008-2009.
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# = Premailer
|
4
|
+
require 'trollop'
|
5
|
+
require File.join(File.dirname(__FILE__), '../lib/premailer')
|
6
|
+
|
7
|
+
opts = Trollop::options do
|
8
|
+
version "Premailer #{Premailer::VERSION} (c) 2008-2009 Alex Dunae"
|
9
|
+
banner <<-EOS
|
10
|
+
Improve the rendering of HTML emails by making CSS inline, converting links and warning about unsupported code.
|
11
|
+
|
12
|
+
Usage:
|
13
|
+
premailer [options] inputfile [outputfile] [warningsfile]
|
14
|
+
|
15
|
+
Example
|
16
|
+
premailer http://example.com/
|
17
|
+
premailer http://example.com/ out.html out.txt warnings.txt
|
18
|
+
premailer --base-url=http://example.com/ src.html out.html
|
19
|
+
|
20
|
+
Options:
|
21
|
+
EOS
|
22
|
+
opt :base_url, "Manually set the base URL, useful for local files", :type => String
|
23
|
+
opt :query_string, "Query string to append to links", :type => String, :short => 'q'
|
24
|
+
opt :line_length, "Length of lines when creating plaintext version", :type => :int, :default => 65, :short => 'l'
|
25
|
+
opt :remove_classes, "Remove classes from the HTML document?", :default => false
|
26
|
+
opt :css, "Manually specify css stylesheets", :type => String, :multi => true
|
27
|
+
opt :verbose, '', :default => false, :short => 'v'
|
28
|
+
end
|
29
|
+
|
30
|
+
inputfile = ARGV.shift
|
31
|
+
outfile = ARGV.shift
|
32
|
+
txtfile = ARGV.shift
|
33
|
+
warningsfile = ARGV.shift
|
34
|
+
|
35
|
+
Trollop::die "inputfile is missing" if inputfile.nil?
|
36
|
+
|
37
|
+
premailer_opts = {
|
38
|
+
:base_url => opts[:base_url],
|
39
|
+
:query_string => opts[:query_string],
|
40
|
+
:show_warnings => opts[:show_warnings] ? Premailer::Warnings::SAFE : Premailer::Warnings::NONE,
|
41
|
+
:line_length => opts[:line_length],
|
42
|
+
:remove_classes => opts[:remove_classes],
|
43
|
+
:css => opts[:css]
|
44
|
+
}
|
45
|
+
|
46
|
+
premailer = Premailer.new(inputfile, premailer_opts)
|
47
|
+
|
48
|
+
# html output
|
49
|
+
if outfile
|
50
|
+
fout = File.open(outfile, 'w')
|
51
|
+
fout.puts premailer.to_inline_css
|
52
|
+
fout.close
|
53
|
+
else
|
54
|
+
p premailer.to_inline_css
|
55
|
+
exit
|
56
|
+
end
|
57
|
+
|
58
|
+
# plaintext output
|
59
|
+
if txtfile
|
60
|
+
fout = File.open(txtfile, 'w')
|
61
|
+
fout.puts premailer.to_plain_text
|
62
|
+
fout.close
|
63
|
+
end
|
64
|
+
|
65
|
+
# warnings output
|
66
|
+
if warningsfile
|
67
|
+
fout = File.open(warningsfile, 'w')
|
68
|
+
premailer.warnings.each do |w|
|
69
|
+
fout.puts "- #{w[:message]} (#{w[:level]}) may not render properly in #{w[:clients]}"
|
70
|
+
end
|
71
|
+
fout.close
|
72
|
+
end
|