mail_style 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,75 @@
1
+ # encoding: utf-8
2
+ require 'rake'
3
+ require 'rake/rdoctask'
4
+
5
+ begin
6
+ require 'spec/rake/spectask'
7
+ rescue LoadError
8
+ begin
9
+ gem 'rspec-rails', '>= 1.0.0'
10
+ require 'spec/rake/spectask'
11
+ rescue LoadError
12
+ puts "RSpec - or one of its dependencies - is not available. Install it with: sudo gem install rspec-rails"
13
+ end
14
+ end
15
+
16
+ NAME = "mail_style"
17
+ SUMMARY = %{Making HTML emails a little less painful. Writes css inline and corrects image urls.}
18
+ HOMEPAGE = "http://github.com/purify/mail_style"
19
+ AUTHOR = "Jim Neath"
20
+ EMAIL = "jimneath@googlemail.com"
21
+ SUPPORT_FILES = %w(readme.textile)
22
+
23
+ begin
24
+ gem 'jeweler', '>= 1.0.0'
25
+ require 'jeweler'
26
+
27
+ Jeweler::Tasks.new do |t|
28
+ t.name = NAME
29
+ t.summary = SUMMARY
30
+ t.email = EMAIL
31
+ t.homepage = HOMEPAGE
32
+ t.description = SUMMARY
33
+ t.author = AUTHOR
34
+
35
+ t.require_path = 'lib'
36
+ t.files = SUPPORT_FILES << %w(Rakefile) << Dir.glob(File.join(*%w[{lib,spec} ** *]).to_s)
37
+ t.extra_rdoc_files = SUPPORT_FILES
38
+
39
+ t.add_dependency 'action_mailer', '>= 1.2.3'
40
+ t.add_dependency 'nokogiri', '>= 1.0.0'
41
+ t.add_dependency 'css_parser', '>= 1.0.0'
42
+
43
+ t.add_development_dependency 'rspec-rails', '>= 1.2.6'
44
+ end
45
+
46
+ Jeweler::GemcutterTasks.new
47
+ rescue LoadError
48
+ puts "Jeweler - or one of its dependencies - is not available. Install it with: sudo gem install jeweler -s http://gemcutter.org"
49
+ end
50
+
51
+ desc "Default: Run specs."
52
+ task :default => :spec
53
+
54
+ desc "Generate documentation for the #{NAME} plugin."
55
+ Rake::RDocTask.new(:rdoc) do |t|
56
+ t.rdoc_dir = 'rdoc'
57
+ t.title = NAME
58
+ t.options << '--line-numbers' << '--inline-source'
59
+ t.rdoc_files.include(SUPPORT_FILES)
60
+ t.rdoc_files.include('lib/**/*.rb')
61
+ end
62
+
63
+ if defined?(Spec)
64
+ desc "Run plugin specs for #{NAME}."
65
+ Spec::Rake::SpecTask.new('spec') do |t|
66
+ t.spec_files = FileList['spec/**/*_spec.rb']
67
+ t.spec_opts = ["-c"]
68
+ end
69
+
70
+ desc "Run plugin specs for #{NAME} with specdoc formatting and colors"
71
+ Spec::Rake::SpecTask.new('specdoc') do |t|
72
+ t.spec_files = FileList['spec/**/*_spec.rb']
73
+ t.spec_opts = ["--format specdoc", "-c"]
74
+ end
75
+ end
@@ -0,0 +1,6 @@
1
+ require 'mail_style/inline_styles'
2
+ require 'mail_style/sass_support' if defined?(Sass)
3
+
4
+ module MailStyle
5
+ class CSSFileNotFound < StandardError; end
6
+ end
@@ -0,0 +1,167 @@
1
+ require 'uri'
2
+ require 'nokogiri'
3
+ require 'css_parser'
4
+
5
+ module MailStyle
6
+ module InlineStyles
7
+ DOCTYPE = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
8
+
9
+ module InstanceMethods
10
+ def create_mail_with_inline_styles
11
+ write_inline_styles if @css.present?
12
+ create_mail_without_inline_styles
13
+ end
14
+
15
+ protected
16
+
17
+ def write_inline_styles
18
+ # Parse only text/html parts
19
+ @parts.select{|p| p.content_type == 'text/html'}.each do |part|
20
+ part.body = parse_html(part.body)
21
+ end
22
+
23
+ # Parse single part emails if the body is html
24
+ real_content_type, ctype_attrs = parse_content_type
25
+ self.body = parse_html(body) if body.is_a?(String) && real_content_type == 'text/html'
26
+ end
27
+
28
+ def parse_html(html)
29
+ # Parse original html
30
+ html_document = create_html_document(html)
31
+ html_document = absolutize_image_sources(html_document)
32
+
33
+ # Write inline styles
34
+ element_styles = {}
35
+
36
+ css_parser.each_selector do |selector, declaration, specificity|
37
+ html_document.css(selector).each do |element|
38
+ declaration.to_s.split(';').each do |style|
39
+ # Split style in attribute and value
40
+ attribute, value = style.split(':').map(&:strip)
41
+
42
+ # Set element style defaults
43
+ element_styles[element] ||= {}
44
+ element_styles[element][attribute] ||= { :specificity => 0, :value => '' }
45
+
46
+ # Update attribute value if specificity is higher than previous values
47
+ if element_styles[element][attribute][:specificity] <= specificity
48
+ element_styles[element][attribute] = { :specificity => specificity, :value => value }
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ # Loop through element styles
55
+ element_styles.each_pair do |element, attributes|
56
+ # Elements current styles
57
+ current_style = element['style'].to_s.split(';').sort
58
+
59
+ # Elements new styles
60
+ new_style = attributes.map{|attribute, style| "#{attribute}: #{update_image_urls(style[:value])}"}
61
+
62
+ # Concat styles
63
+ style = (current_style + new_style).compact.uniq.map(&:strip).sort
64
+
65
+ # Set new styles
66
+ element['style'] = style.join(';')
67
+ end
68
+
69
+ # Strip all references to classes.
70
+ html_document.css('*').remove_class
71
+ html_document.to_html
72
+ end
73
+
74
+ def absolutize_image_sources(document)
75
+ document.css('img').each do |img|
76
+ src = img['src']
77
+ img['src'] = src.gsub(src, absolutize_url(src))
78
+ end
79
+
80
+ document
81
+ end
82
+
83
+ # Create Nokogiri html document from part contents and add/amend certain elements.
84
+ # Reference: http://www.creativeglo.co.uk/email-design/html-email-design-and-coding-tips-part-2/
85
+ def create_html_document(body)
86
+ # Add doctype to html along with body
87
+ document = Nokogiri::HTML.parse(DOCTYPE + body)
88
+
89
+ # Set some meta stuff
90
+ html = document.at_css('html')
91
+ html['xmlns'] = 'http://www.w3.org/1999/xhtml'
92
+
93
+ # Create <head> element if missing
94
+ head = document.at_css('head')
95
+
96
+ unless head.present?
97
+ head = Nokogiri::XML::Node.new('head', document)
98
+ document.at_css('body').add_previous_sibling(head)
99
+ end
100
+
101
+ # Add utf-8 content type meta tag
102
+ meta = Nokogiri::XML::Node.new('meta', document)
103
+ meta['http-equiv'] = 'Content-Type'
104
+ meta['content'] = 'text/html; charset=utf-8'
105
+ head.add_child(meta)
106
+
107
+ # Return document
108
+ document
109
+ end
110
+
111
+ # Update image urls
112
+ def update_image_urls(style)
113
+ if default_url_options[:host].present?
114
+ # Replace urls in stylesheets
115
+ style.gsub!($1, absolutize_url($1, 'stylesheets')) if style[/url\(['"]?(.*)['"]?\)/i]
116
+ end
117
+
118
+ style
119
+ end
120
+
121
+ # Absolutize URL (Absolutize? Seriously?)
122
+ def absolutize_url(url, base_path = '')
123
+ original_url = url
124
+
125
+ unless original_url[URI::regexp(%w[http https])]
126
+ # Calculate new path
127
+ host = default_url_options[:host]
128
+ url = URI.join("http://#{host}/", File.join(base_path, original_url)).to_s
129
+ end
130
+
131
+ url
132
+ end
133
+
134
+ # Css Parser
135
+ def css_parser
136
+ parser = CssParser::Parser.new
137
+ parser.add_block!(css_rules)
138
+ parser
139
+ end
140
+
141
+ # Css Rules
142
+ def css_rules
143
+ File.read(css_file)
144
+ end
145
+
146
+ # Find the css file
147
+ def css_file
148
+ if @css.present?
149
+ css = @css.to_s
150
+ css = css[/\.css$/] ? css : "#{css}.css"
151
+ path = File.join(RAILS_ROOT, 'public', 'stylesheets', css)
152
+ File.exist?(path) ? path : raise(CSSFileNotFound)
153
+ end
154
+ end
155
+ end
156
+
157
+ def self.included(receiver)
158
+ receiver.send :include, InstanceMethods
159
+ receiver.class_eval do
160
+ adv_attr_accessor :css
161
+ alias_method_chain :create_mail, :inline_styles
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ ActionMailer::Base.send :include, MailStyle::InlineStyles
@@ -0,0 +1,15 @@
1
+ module MailStyle
2
+ module InlineStyles
3
+ module InstanceMethods
4
+ def css_file_with_sass
5
+ if !Sass::Plugin.checked_for_updates || Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
6
+ Sass::Plugin.update_stylesheets
7
+ end
8
+
9
+ css_file_without_sass
10
+ end
11
+
12
+ alias_method_chain :css_file, :sass
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,82 @@
1
+ h1. MailStyle
2
+
3
+ MailStyle tries to make sending HTML emails a little less painful.
4
+
5
+ For a more in depth introduction check out the "Blog Post":http://blog.purifyapp.com/2009/12/30/mailstyle-a-html-email-plugin-for-ruby-on-rails/
6
+
7
+ It was developed for use on "Purify: Awesome Bug & Issue Tracking":http://purifyapp.com
8
+
9
+ h2. Install
10
+
11
+ First install the dependencies:
12
+
13
+ <pre><code>sudo gem install nokogiri css_parser</code></pre>
14
+
15
+ Then install MailStyle to your rails app, either as a plugin:
16
+
17
+ <pre><code>script/plugin install http://github.com/purify/mail_style</code></pre>
18
+
19
+ Or you can install the gem:
20
+
21
+ <pre><code>sudo gem install mail_style</code></pre>
22
+
23
+ Then in your <code>environment.rb</code> file add:
24
+
25
+ <pre><code>config.gem "mail_style"</code></pre>
26
+
27
+ h2. Usage
28
+
29
+ Simply add the <code>css</code> method to your deliver actions:
30
+
31
+ <pre><code>class Notifier < ActionMailer::Base
32
+ def welcome_email
33
+ css :email
34
+
35
+ subject 'Welcome Aboard'
36
+ recipients 'someone@example.com'
37
+ from 'jimneath@googlemail.com'
38
+ sent_on Time.now
39
+ end
40
+ end</code></pre>
41
+
42
+ This will look for a css file called _email.css_ in your _public/stylesheets_ folder. The <code>css</code> method can take either a string or a symbol. You can also pass the css file name with or without the .css extension.
43
+
44
+ h2. Image URL Correcting
45
+
46
+ If you have _default_url_options[:host]_ set in your mailer, then MailStyle will do it's best to make the urls of images absolute.
47
+
48
+ h4. In your mailer
49
+
50
+ <pre><code>ActionMailer::Base.default_url_options[:host] = "example.com"</code></pre>
51
+
52
+ h2. Features
53
+
54
+ * Write CSS styles inline
55
+ * Corrects image urls
56
+ * SASS Support
57
+
58
+ h2. Bugs / Todo
59
+
60
+ * Improve overall performance
61
+ * Add support for less
62
+ * Allow users to swap between css_parser and csspool
63
+
64
+ h2. Contributors
65
+
66
+ * "Jim Neath":http://jimneath.org
67
+ * "Lars Klevans":http://tastybyte.blogspot.com/
68
+ * "Jonas Grimfelt":http://github.com/grimen
69
+
70
+ h2. License
71
+
72
+ (The MIT License)
73
+
74
+ Copyright &copy; 2009-2010
75
+
76
+ * "Jim Neath":http://jimneath.org
77
+
78
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
79
+
80
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
81
+
82
+ THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,190 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ RAILS_ROOT = File.join(File.dirname(__FILE__), '../../../../')
5
+
6
+ # Set ActionMailer stuff
7
+ ActionMailer::Base.template_root = '.'
8
+ ActionMailer::Base.delivery_method = :test
9
+ ActionMailer::Base.perform_deliveries = true
10
+ ActionMailer::Base.deliveries = []
11
+ ActionMailer::Base.default_url_options[:host] = "example.com"
12
+
13
+ # Test Mailer
14
+ class TestMailer < ActionMailer::Base
15
+ def test_multipart(css_file = nil)
16
+ setup_email(css_file)
17
+ content_type 'multipart/alternative'
18
+ part :content_type => 'text/html', :body => '<p class="text">Hello World</p>'
19
+ part :content_type => 'text/plain', :body => 'Hello World'
20
+ end
21
+
22
+ def test_singlepart_html(css_file = nil)
23
+ setup_email(css_file)
24
+ content_type 'text/html'
25
+ body '<p class="text">Hello World</p>'
26
+ end
27
+
28
+ def test_singlepart_plain(css_file = nil)
29
+ setup_email(css_file)
30
+ content_type 'text/plain'
31
+ body '<p class="text">Hello World</p>'
32
+ end
33
+
34
+ def test_image_urls(css_file = nil)
35
+ setup_email(css_file)
36
+ content_type 'multipart/alternative'
37
+ part :content_type => 'text/html', :body => '<p id="image">Hello World</p><img src="/images/test.jpg" />'
38
+ part :content_type => 'text/plain', :body => 'Hello World'
39
+ end
40
+
41
+ protected
42
+
43
+ def setup_email(css_file = nil)
44
+ css css_file unless css_file.nil?
45
+
46
+ subject 'Test Multipart Email'
47
+ recipients 'jimneath@googlemail.com'
48
+ from 'jimneath@googlemail.com'
49
+ sent_on Time.now
50
+ end
51
+ end
52
+
53
+ describe 'Inline styles' do
54
+ describe 'singlepart' do
55
+ before(:each) do
56
+ css_rules <<-EOF
57
+ body { background: #000 }
58
+ p { color: #f00; line-height: 1.5 }
59
+ .text { font-size: 14px }
60
+ EOF
61
+ end
62
+
63
+ it "should apply styles for text/html" do
64
+ @email = TestMailer.deliver_test_singlepart_html(:real)
65
+ @email.body.should match(/<body style="background: #000">/)
66
+ end
67
+
68
+ it "should do nothing for text/plain" do
69
+ @email = TestMailer.deliver_test_singlepart_plain(:real)
70
+ @email.body.should eql('<p class="text">Hello World</p>')
71
+ end
72
+ end
73
+
74
+ describe 'multipart' do
75
+ describe 'image urls' do
76
+ before(:each) do
77
+ # CSS rules
78
+ css_rules <<-EOF
79
+ p#image { background: url(../images/test-image.png)}
80
+ EOF
81
+
82
+ # Generate email
83
+ @email = TestMailer.deliver_test_image_urls(:real)
84
+ @html = html_part(@email)
85
+ end
86
+
87
+ it "should make the css urls absolute" do
88
+ @html.should match(/<p.*style="background: url\(http:\/\/example\.com\/images\/test\-image\.png\)">/)
89
+ end
90
+
91
+ it "should make image sources absolute" do
92
+ # Note: Nokogiri loses the closing slash from the <img> tag for some reason.
93
+ @html.should match(/<img src="http:\/\/example\.com\/images\/test\.jpg\">/)
94
+ end
95
+ end
96
+
97
+ describe 'rendering inline styles' do
98
+ before(:each) do
99
+ css_rules <<-EOF
100
+ body { background: #000 }
101
+ .text { color: #0f0; font-size: 14px }
102
+ p { color: #f00; line-height: 1.5 }
103
+ EOF
104
+
105
+ # Generate email
106
+ @email = TestMailer.deliver_test_multipart(:real)
107
+ @html = html_part(@email)
108
+ end
109
+
110
+ it "should add the correct xml namespace" do
111
+ @html.should match(/<html xmlns="http:\/\/www\.w3\.org\/1999\/xhtml">/)
112
+ end
113
+
114
+ it "should write the xhtml 1.0 doctype" do
115
+ @html.should match(/<!DOCTYPE html PUBLIC "-\/\/W3C\/\/DTD XHTML 1\.0 Transitional\/\/EN" "http:\/\/www.w3.org\/TR\/xhtml1\/DTD\/xhtml1-transitional\.dtd">/mi)
116
+ end
117
+
118
+ it "should write utf-8 content type meta tag" do
119
+ @html.should match(/<head>.*<meta http\-equiv="Content\-Type" content="text\/html; charset=utf\-8">.*<\/head>/mi)
120
+ end
121
+
122
+ it "should wrap with html and body tag if missing" do
123
+ @html.should match(/<html.*>.*<body.*>.*<\/body>.*<\/html>/m)
124
+ end
125
+
126
+ it "should add style to body" do
127
+ @html.should match(/<body style="background: #000">/)
128
+ end
129
+
130
+ it "should remove classes from html" do
131
+ @html.should_not match(/<p.*class="text".*>/)
132
+ end
133
+
134
+ it "should add both styles to paragraph" do
135
+ @html.should match(/<p style="color: #0f0;font-size: 14px;line-height: 1.5">/)
136
+ end
137
+ end
138
+
139
+ describe 'combining styles' do
140
+ it "should select the most specific style" do
141
+ css_rules <<-EOF
142
+ .text { color: #0f0; }
143
+ p { color: #f00; }
144
+ EOF
145
+ @email = TestMailer.deliver_test_multipart(:real)
146
+ @html = html_part(@email)
147
+ @html.should match(/<p style="color: #0f0">/)
148
+ end
149
+ it "should combine different properties for one element" do
150
+ css_rules <<-EOF
151
+ .text { font-size: 14px; }
152
+ p { color: #f00; }
153
+ EOF
154
+ @email = TestMailer.deliver_test_multipart(:real)
155
+ @html = html_part(@email)
156
+ @html.should match(/<p style="color: #f00;font-size: 14px">/)
157
+ end
158
+ end
159
+
160
+ describe 'css file' do
161
+ it "should do nothing if no css file is set" do
162
+ @email = TestMailer.deliver_test_multipart(nil)
163
+ html_part(@email).should eql('<p class="text">Hello World</p>')
164
+ end
165
+
166
+ it "should raise MailStyle::CSSFileNotFound if css file does not exist" do
167
+ lambda {
168
+ TestMailer.deliver_test_multipart(:fake)
169
+ }.should raise_error(MailStyle::CSSFileNotFound)
170
+ end
171
+ end
172
+
173
+ it 'should support inline styles without deliver' do
174
+ css_rules <<-EOF
175
+ body { background: #000 }
176
+ p { color: #f00; line-height: 1.5 }
177
+ .text { font-size: 14px }
178
+ EOF
179
+
180
+ # Generate email
181
+ @email = TestMailer.create_test_multipart(:real)
182
+ html_part(@email).should match(/<body style="background: #000">/)
183
+ end
184
+
185
+ it "should have two parts" do
186
+ @email = TestMailer.deliver_test_multipart
187
+ @email.parts.length.should eql(2)
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format s
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,30 @@
1
+ $: << File.dirname(__FILE__) + '/../lib'
2
+
3
+ require 'rubygems'
4
+ require 'spec'
5
+ require 'action_mailer'
6
+ require 'mail_style'
7
+
8
+ # Extract HTML Part
9
+ def html_part(email)
10
+ email.parts.select{|part| part.content_type == 'text/html'}.first.body
11
+ end
12
+
13
+ def css_rules(css)
14
+ @css_rules = css
15
+
16
+ # Stubs
17
+ File.stub(:exist?).and_return(true)
18
+ File.stub(:read).and_return(@css_rules)
19
+ end
20
+
21
+ # Debugging helper
22
+ module Kernel
23
+ if ENV.keys.find {|env_var| env_var.match(/^TM_/)}
24
+ def rputs(*args)
25
+ puts( *["<pre>", args.collect {|a| CGI.escapeHTML(a.to_s)}, "</pre>"])
26
+ end
27
+ else
28
+ alias_method :rputs, :puts
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mail_style
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Jim Neath
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-02 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: action_mailer
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.3
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: nokogiri
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: css_parser
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.0
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: rspec-rails
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.2.6
54
+ version:
55
+ description: Making HTML emails a little less painful. Writes css inline and corrects image urls.
56
+ email: jimneath@googlemail.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - Rakefile
63
+ - lib/mail_style.rb
64
+ - lib/mail_style/inline_styles.rb
65
+ - lib/mail_style/sass_support.rb
66
+ - readme.textile
67
+ - spec/inline_styles_spec.rb
68
+ - spec/spec.opts
69
+ - spec/spec_helper.rb
70
+ files:
71
+ - Rakefile
72
+ - lib/mail_style.rb
73
+ - lib/mail_style/inline_styles.rb
74
+ - lib/mail_style/sass_support.rb
75
+ - readme.textile
76
+ - spec/inline_styles_spec.rb
77
+ - spec/spec.opts
78
+ - spec/spec_helper.rb
79
+ has_rdoc: true
80
+ homepage: http://github.com/purify/mail_style
81
+ licenses: []
82
+
83
+ post_install_message:
84
+ rdoc_options:
85
+ - --charset=UTF-8
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: "0"
93
+ version:
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: "0"
99
+ version:
100
+ requirements: []
101
+
102
+ rubyforge_project:
103
+ rubygems_version: 1.3.5
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: Making HTML emails a little less painful. Writes css inline and corrects image urls.
107
+ test_files:
108
+ - spec/inline_styles_spec.rb
109
+ - spec/spec_helper.rb