kafka_mailer 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3295f7b9bec090e10f821b20369619dd697ad861
4
+ data.tar.gz: cfc2e4da1a2e377b0b55965095c4b058729640a0
5
+ SHA512:
6
+ metadata.gz: 5231ebe7df6e96e3389bfc315ed84b113237128eaf2a31d9801452790f1cbde885de64a7ee20cb3d5919afa3e14d4c792066f22b8731146d2a8ec48d110decfc
7
+ data.tar.gz: 87dd4fce1c44543f412ed1b7ea9c6dc244b8c343e5c254bfe473367261c088ae1550fea03c6d991bd32614d87381311f0b9a3618083cd86dd529d9b0093df50d
@@ -0,0 +1,3 @@
1
+ ## 0.0.1 ##
2
+
3
+ * Initial relase
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "codeclimate-test-reporter", group: :test, require: nil
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Eric Hayes
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.
@@ -0,0 +1,37 @@
1
+ # kafka_mailer [![Build Status](https://travis-ci.org/ejhayes/kafka_mailer.svg?branch=master)](https://travis-ci.org/ejhayes/kafka_mailer) [![Gem Version](https://badge.fury.io/rb/kafka_mailer.svg)](http://badge.fury.io/rb/kafka_mailer) [![Code Climate](https://codeclimate.com/github/ejhayes/kafka_mailer/badges/gpa.svg)](https://codeclimate.com/github/ejhayes/kafka_mailer) [![Test Coverage](https://codeclimate.com/github/ejhayes/kafka_mailer/badges/coverage.svg)](https://codeclimate.com/github/ejhayes/kafka_mailer) [![Dependency Status](https://gemnasium.com/ejhayes/kafka_mailer.svg)](https://gemnasium.com/ejhayes/kafka_mailer)
2
+
3
+ Use [Apache Kafka](http://kafka.apache.org/) as a delivery_method in rails.
4
+
5
+ ## Rails Setup
6
+
7
+ **IMPORTANT**: This is under development right now and is not yet ready for use in a production environment.
8
+
9
+ First add the gem to your development environment and run the +bundle+ command to install it.
10
+
11
+ gem "kafka_mailer"
12
+
13
+ Then set the delivery method in `config/environments/development.rb`
14
+
15
+ config.action_mailer.delivery_method = :kafka
16
+
17
+ Now your emails will be sent to a kafka message queue.
18
+
19
+ ## Hacking on this gem
20
+
21
+ Once you have the source, you must run the following:
22
+
23
+ bundle
24
+ bundle exec rake spec
25
+
26
+ ## TODO
27
+
28
+ Some items that will eventually need to be done:
29
+
30
+ - provide a config block that can specify the structure of the message being sent to kafka
31
+
32
+
33
+ ## Thanks to
34
+
35
+ - Ryan Bates and his [letter_opener](https://github.com/ryanb/letter_opener) which was used as the base for this gem
36
+ - [poseidon](https://github.com/bpot/poseidon) gem for interacting with Apache Kafka
37
+ - [Apache kafka](http://kafka.apache.org/)
@@ -0,0 +1,22 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
9
+ desc 'Interactive console with gem pre-loaded'
10
+ task :console do
11
+ require 'irb'
12
+ require 'irb/completion'
13
+ require 'ruby-debug'
14
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
15
+
16
+ # load the gem
17
+ require 'kafka_mailer'
18
+
19
+ ARGV.clear
20
+ puts "Console Ready!"
21
+ IRB.start
22
+ end
@@ -0,0 +1,8 @@
1
+ require "fileutils"
2
+ require "digest/sha1"
3
+ require "cgi"
4
+ require "uri"
5
+
6
+ require "kafka_mailer/message"
7
+ require "kafka_mailer/delivery_method"
8
+ require "kafka_mailer/railtie" if defined? Rails
@@ -0,0 +1,18 @@
1
+ module KafkaMailer
2
+ class DeliveryMethod
3
+ class InvalidOption < StandardError; end
4
+
5
+ attr_accessor :settings
6
+
7
+ def initialize(options = {})
8
+ raise InvalidOption, "A location option is required when using the kafka delivery method" if options[:location].nil?
9
+ self.settings = options
10
+ end
11
+
12
+ def deliver!(mail)
13
+ byebug
14
+ location = File.join(settings[:location], "#{Time.now.to_i}_#{Digest::SHA1.hexdigest(mail.encoded)[0..6]}")
15
+ messages = Message.rendered_messages(location, mail)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,125 @@
1
+ <html>
2
+ <head>
3
+ <meta http-equiv="Content-Type" content="text/html; charset=<%= encoding %>">
4
+ <% if mail.subject %>
5
+ <title><%= h mail.subject %></title>
6
+ <% end %>
7
+
8
+ <style type="text/css">
9
+ #container {
10
+ margin: 10px auto;
11
+ }
12
+ #message_headers {
13
+ background: #fff;
14
+ font-size: 12px;
15
+ font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
16
+ border-bottom: 1px solid #dedede;
17
+ margin-bottom: 10px;
18
+ overflow: auto;
19
+ }
20
+
21
+ #message_headers dl {
22
+ float: left;
23
+ line-height: 1.3em;
24
+ padding: 0;
25
+ }
26
+
27
+ #message_headers dt {
28
+ width: 92px;
29
+ margin: 0;
30
+ float: left;
31
+ text-align: right;
32
+ font-weight: bold;
33
+ color: #7f7f7f;
34
+ }
35
+
36
+ #message_headers dd {
37
+ margin: 0 0 0 102px;
38
+ }
39
+
40
+ #message_headers p.alternate {
41
+ float: right;
42
+ margin: 0;
43
+ }
44
+
45
+ #message_headers p.alternate a {
46
+ color: #09c;
47
+ }
48
+
49
+ pre#message_body {
50
+ padding: 4px;
51
+ white-space: pre-wrap;
52
+ border: 1px solid #eee;
53
+ background-color: #fcfcfc;
54
+ }
55
+ </style>
56
+ </head>
57
+ <body>
58
+ <div id="container">
59
+ <div id="message_headers">
60
+ <dl>
61
+ <dt>From:</dt>
62
+ <dd><%= h from %></dd>
63
+
64
+ <% unless sender.empty? %>
65
+ <dt>Sender:</dt>
66
+ <dd><%= h sender %></dd>
67
+ <% end %>
68
+
69
+ <% unless reply_to.empty? %>
70
+ <dt>Reply-To:</dt>
71
+ <dd><%= h reply_to %></dd>
72
+ <% end %>
73
+
74
+ <% if mail.subject %>
75
+ <dt>Subject:</dt>
76
+ <dd><strong><%= h mail.subject %></strong></dd>
77
+ <% end %>
78
+
79
+ <dt>Date:</dt>
80
+ <dd><%= Time.now.strftime("%b %e, %Y %I:%M:%S %p %Z") %></dd>
81
+
82
+ <% unless to.empty? %>
83
+ <dt>To:</dt>
84
+ <dd><%= h to %></dd>
85
+ <% end %>
86
+
87
+ <% unless cc.empty? %>
88
+ <dt>CC:</dt>
89
+ <dd><%= h cc %></dd>
90
+ <% end %>
91
+
92
+ <% unless bcc.empty? %>
93
+ <dt>BCC:</dt>
94
+ <dd><%= h bcc %></dd>
95
+ <% end %>
96
+
97
+ <% if @attachments.any? %>
98
+ <dt>Attachments:</dt>
99
+ <dd>
100
+ <% @attachments.each do |filename, path| %>
101
+ <a href="<%= path %>"><%= filename %></a>&nbsp;
102
+ <% end %>
103
+ </dd>
104
+ <% end %>
105
+ </dl>
106
+
107
+ <% if mail.multipart? %>
108
+ <p class="alternate">
109
+ <% if type == "plain" && mail.html_part %>
110
+ <a href="rich.html">View HTML version</a>
111
+ <% elsif type == "rich" && mail.text_part %>
112
+ <a href="plain.html">View plain text version</a>
113
+ <% end %>
114
+ </p>
115
+ <% end %>
116
+ </div>
117
+
118
+ <% if type == "plain" %>
119
+ <pre id="message_body"><%= auto_link(h(body)) %></pre>
120
+ <% else %>
121
+ <%= body %>
122
+ <% end %>
123
+ </div>
124
+ </body>
125
+ </html>
@@ -0,0 +1,117 @@
1
+ require "erb"
2
+
3
+ module KafkaMailer
4
+ class Message
5
+ attr_reader :mail
6
+
7
+ def self.rendered_messages(location, mail)
8
+ messages = []
9
+ messages << new(location, mail, mail.html_part) if mail.html_part
10
+ messages << new(location, mail, mail.text_part) if mail.text_part
11
+ messages << new(location, mail) if messages.empty?
12
+ messages.each(&:render)
13
+ messages.sort
14
+ end
15
+
16
+ def initialize(location, mail, part = nil)
17
+ @location = location
18
+ @mail = mail
19
+ @part = part
20
+ @attachments = []
21
+ end
22
+
23
+ def render
24
+ FileUtils.mkdir_p(@location)
25
+
26
+ if mail.attachments.any?
27
+ attachments_dir = File.join(@location, 'attachments')
28
+ FileUtils.mkdir_p(attachments_dir)
29
+ mail.attachments.each do |attachment|
30
+ filename = attachment.filename.gsub(/[^\w.]/, '_')
31
+ path = File.join(attachments_dir, filename)
32
+
33
+ unless File.exists?(path) # true if other parts have already been rendered
34
+ File.open(path, 'wb') { |f| f.write(attachment.body.raw_source) }
35
+ end
36
+
37
+ @attachments << [attachment.filename, "attachments/#{URI.escape(filename)}"]
38
+ end
39
+ end
40
+
41
+ File.open(filepath, 'w') do |f|
42
+ f.write ERB.new(template).result(binding)
43
+ end
44
+ end
45
+
46
+ def template
47
+ File.read(File.expand_path("../message.html.erb", __FILE__))
48
+ end
49
+
50
+ def filepath
51
+ File.join(@location, "#{type}.html")
52
+ end
53
+
54
+ def content_type
55
+ @part && @part.content_type || @mail.content_type
56
+ end
57
+
58
+ def body
59
+ @body ||= begin
60
+ body = (@part || @mail).decoded
61
+
62
+ mail.attachments.each do |attachment|
63
+ body.gsub!(attachment.url, "attachments/#{attachment.filename}")
64
+ end
65
+
66
+ body
67
+ end
68
+ end
69
+
70
+ def from
71
+ @from ||= Array(@mail['from']).join(", ")
72
+ end
73
+
74
+ def sender
75
+ @sender ||= Array(@mail['sender']).join(", ")
76
+ end
77
+
78
+ def to
79
+ @to ||= Array(@mail['to']).join(", ")
80
+ end
81
+
82
+ def cc
83
+ @cc ||= Array(@mail['cc']).join(", ")
84
+ end
85
+
86
+ def bcc
87
+ @bcc ||= Array(@mail['bcc']).join(", ")
88
+ end
89
+
90
+ def reply_to
91
+ @reply_to ||= Array(@mail['reply-to']).join(", ")
92
+ end
93
+
94
+ def type
95
+ content_type =~ /html/ ? "rich" : "plain"
96
+ end
97
+
98
+ def encoding
99
+ body.respond_to?(:encoding) ? body.encoding : "utf-8"
100
+ end
101
+
102
+ def auto_link(text)
103
+ text.gsub(URI.regexp(%W[https http])) do |link|
104
+ "<a href=\"#{ link }\">#{ link }</a>"
105
+ end
106
+ end
107
+
108
+ def h(content)
109
+ CGI.escapeHTML(content)
110
+ end
111
+
112
+ def <=>(other)
113
+ order = %w[rich plain]
114
+ order.index(type) <=> order.index(other.type)
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,9 @@
1
+ module KafkaMailer
2
+ class Railtie < Rails::Railtie
3
+ initializer "letter_opener.add_delivery_method" do
4
+ ActiveSupport.on_load :action_mailer do
5
+ ActionMailer::Base.add_delivery_method :kafka, KafkaMailer::DeliveryMethod, :location => Rails.root.join("tmp", "kafka_mailer")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,277 @@
1
+ require "spec_helper"
2
+
3
+ describe KafkaMailer::DeliveryMethod do
4
+ let(:location) { File.expand_path('../../../tmp/kafka_mailer', __FILE__) }
5
+
6
+ let(:plain_file) { Dir["#{location}/*/plain.html"].first }
7
+ let(:plain) { CGI.unescape_html(File.read(plain_file)) }
8
+
9
+ before do
10
+ # TODO: STUB kafka connection
11
+ context = self
12
+
13
+ Mail.defaults do
14
+ delivery_method KafkaMailer::DeliveryMethod, :location => context.location
15
+ end
16
+ end
17
+
18
+ it 'raises an exception if no location passed' do
19
+ # expect { KafkaMailer::DeliveryMethod.new }.to raise_exception(KafkaMailer::DeliveryMethod::InvalidOption)
20
+ # expect { KafkaMailer::DeliveryMethod.new(location: "foo") }.to_not raise_exception
21
+ end
22
+
23
+ context 'integration' do
24
+
25
+ #context 'normal location path' do
26
+ # it 'opens email' do
27
+ # expect($stdout).to receive(:puts)
28
+ # expect {
29
+ # Mail.deliver do
30
+ # from 'Foo foo@example.com'
31
+ # body 'World! http://example.com'
32
+ # end
33
+ # }.not_to raise_error
34
+ # end
35
+ #end
36
+
37
+ #context 'with spaces in location path' do
38
+ # let(:location) { File.expand_path('../../../tmp/kafka_mailer with space', __FILE__) }
39
+ #
40
+ # it 'opens email' do
41
+ # expect($stdout).to receive(:puts)
42
+ # expect {
43
+ # Mail.deliver do
44
+ # from 'Foo foo@example.com'
45
+ # body 'World! http://example.com'
46
+ # end
47
+ # }.not_to raise_error
48
+ # end
49
+ #end
50
+ end
51
+
52
+ context 'content' do
53
+ context 'plain' do
54
+ before do
55
+ #expect(Launchy).to receive(:open)
56
+
57
+ Mail.deliver do
58
+ from 'Foo <foo@example.com>'
59
+ sender 'Baz <baz@example.com>'
60
+ reply_to 'No Reply <no-reply@example.com>'
61
+ to 'Bar <bar@example.com>'
62
+ cc 'Qux <qux@example.com>'
63
+ bcc 'Qux <qux@example.com>'
64
+ subject 'Hello'
65
+ body 'World! http://example.com'
66
+ end
67
+ end
68
+
69
+ # TODO: check message queue getting correct params
70
+ #it 'creates plain html document' do
71
+ # expect(File.exist?(plain_file)).to be_true
72
+ #end
73
+ #
74
+ #it 'saves From field' do
75
+ # expect(plain).to include("Foo <foo@example.com>")
76
+ #end
77
+ #
78
+ #it 'saves Sender field' do
79
+ # expect(plain).to include("Baz <baz@example.com>")
80
+ #end
81
+ #
82
+ #it 'saves Reply-to field' do
83
+ # expect(plain).to include("No Reply <no-reply@example.com>")
84
+ #end
85
+ #
86
+ #it 'saves To field' do
87
+ # expect(plain).to include("Bar <bar@example.com>")
88
+ #end
89
+ #
90
+ #it 'saves Subject field' do
91
+ # expect(plain).to include("Hello")
92
+ #end
93
+ #
94
+ #it 'saves Body with autolink' do
95
+ # expect(plain).to include('World! <a href="http://example.com">http://example.com</a>')
96
+ #end
97
+ end
98
+
99
+ context 'multipart' do
100
+ let(:rich_file) { Dir["#{location}/*/rich.html"].first }
101
+ let(:rich) { CGI.unescape_html(File.read(rich_file)) }
102
+
103
+ before do
104
+ #expect(Launchy).to receive(:open)
105
+
106
+ Mail.deliver do
107
+ from 'foo@example.com'
108
+ to 'bar@example.com'
109
+ subject 'Many parts with <html>'
110
+ text_part do
111
+ body 'This is <plain> text'
112
+ end
113
+ html_part do
114
+ content_type 'text/html; charset=UTF-8'
115
+ body '<h1>This is HTML</h1>'
116
+ end
117
+ end
118
+ end
119
+
120
+ #it 'creates plain html document' do
121
+ # expect(File.exist?(plain_file)).to be_true
122
+ #end
123
+ #
124
+ #it 'creates rich html document' do
125
+ # expect(File.exist?(rich_file)).to be_true
126
+ #end
127
+ #
128
+ #it 'shows link to rich html version' do
129
+ # expect(plain).to include("View HTML version")
130
+ #end
131
+ #
132
+ #it 'saves text part' do
133
+ # expect(plain).to include("This is <plain> text")
134
+ #end
135
+ #
136
+ #it 'saves html part' do
137
+ # expect(rich).to include("<h1>This is HTML</h1>")
138
+ #end
139
+ #
140
+ #it 'saves escaped Subject field' do
141
+ # expect(plain).to include("Many parts with <html>")
142
+ #end
143
+ #
144
+ #it 'shows subject as title' do
145
+ # expect(rich).to include("<title>Many parts with <html></title>")
146
+ #end
147
+ end
148
+ end
149
+
150
+ context 'using deliver! method' do
151
+ before do
152
+ #expect(Launchy).to receive(:open)
153
+ Mail.new do
154
+ from 'foo@example.com'
155
+ to 'bar@example.com'
156
+ subject 'Hello'
157
+ body 'World!'
158
+ end.deliver!
159
+ end
160
+
161
+ #it 'creates plain html document' do
162
+ # expect(File.exist?(plain_file)).to be_true
163
+ #end
164
+ #
165
+ #it 'saves From field' do
166
+ # expect(plain).to include("foo@example.com")
167
+ #end
168
+ #
169
+ #it 'saves To field' do
170
+ # expect(plain).to include("bar@example.com")
171
+ #end
172
+ #
173
+ #it 'saves Subject field' do
174
+ # expect(plain).to include("Hello")
175
+ #end
176
+ #
177
+ #it 'saves Body field' do
178
+ # expect(plain).to include("World!")
179
+ #end
180
+ end
181
+
182
+ context 'attachments in plain text mail' do
183
+ before do
184
+ Mail.deliver do
185
+ from 'foo@example.com'
186
+ to 'bar@example.com'
187
+ subject 'With attachments'
188
+ text_part do
189
+ body 'This is <plain> text'
190
+ end
191
+ attachments[File.basename(__FILE__)] = File.read(__FILE__)
192
+ end
193
+ end
194
+
195
+ #it 'creates attachments dir with attachment' do
196
+ # attachment = Dir["#{location}/*/attachments/#{File.basename(__FILE__)}"].first
197
+ # expect(File.exists?(attachment)).to be_true
198
+ #end
199
+ #
200
+ #it 'saves attachment name' do
201
+ # plain = File.read(Dir["#{location}/*/plain.html"].first)
202
+ # expect(plain).to include(File.basename(__FILE__))
203
+ #end
204
+ end
205
+
206
+ context 'attachments in rich mail' do
207
+ let(:url) { mail.attachments[0].url }
208
+
209
+ let!(:mail) do
210
+ Mail.deliver do
211
+ from 'foo@example.com'
212
+ to 'bar@example.com'
213
+ subject 'With attachments'
214
+ attachments[File.basename(__FILE__)] = File.read(__FILE__)
215
+ url = attachments[0].url
216
+ html_part do
217
+ content_type 'text/html; charset=UTF-8'
218
+ body "Here's an image: <img src='#{url}' />"
219
+ end
220
+ end
221
+ end
222
+
223
+ #it 'creates attachments dir with attachment' do
224
+ # attachment = Dir["#{location}/*/attachments/#{File.basename(__FILE__)}"].first
225
+ # expect(File.exists?(attachment)).to be_true
226
+ #end
227
+ #
228
+ #it 'replaces inline attachment urls' do
229
+ # text = File.read(Dir["#{location}/*/rich.html"].first)
230
+ # expect(mail.parts[0].body).to include(url)
231
+ # expect(text).to_not include(url)
232
+ # expect(text).to include("attachments/#{File.basename(__FILE__)}")
233
+ #end
234
+ end
235
+
236
+ context 'attachments with non-word characters in the filename' do
237
+ before do
238
+ Mail.deliver do
239
+ from 'foo@example.com'
240
+ to 'bar@example.com'
241
+ subject 'With attachments'
242
+ text_part do
243
+ body 'This is <plain> text'
244
+ end
245
+ attachments['non word:chars/used,01.txt'] = File.read(__FILE__)
246
+ end
247
+ end
248
+
249
+ #it 'creates attachments dir with attachment' do
250
+ # attachment = Dir["#{location}/*/attachments/non_word_chars_used_01.txt"].first
251
+ # expect(File.exists?(attachment)).to be_true
252
+ #end
253
+ #
254
+ #it 'saves attachment name' do
255
+ # plain = File.read(Dir["#{location}/*/plain.html"].first)
256
+ # expect(plain).to include('non_word_chars_used_01.txt')
257
+ #end
258
+ end
259
+
260
+
261
+ context 'subjectless mail' do
262
+ before do
263
+ #expect(Launchy).to receive(:open)
264
+
265
+ Mail.deliver do
266
+ from 'Foo foo@example.com'
267
+ reply_to 'No Reply no-reply@example.com'
268
+ to 'Bar bar@example.com'
269
+ body 'World! http://example.com'
270
+ end
271
+ end
272
+
273
+ #it 'creates plain html document' do
274
+ # expect(File.exist?(plain_file)).to be_true
275
+ #end
276
+ end
277
+ end
@@ -0,0 +1,204 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe KafkaMailer::Message do
5
+ let(:location) { File.expand_path('../../../tmp/letter_opener', __FILE__) }
6
+
7
+ def mail(options={}, &blk)
8
+ Mail.new(options, &blk)
9
+ end
10
+
11
+ describe '#reply_to' do
12
+ it 'handles one email as a string' do
13
+ mail = mail(:reply_to => 'test@example.com')
14
+ message = described_class.new(location, mail)
15
+ expect(message.reply_to).to eq('test@example.com')
16
+ end
17
+
18
+ it 'handles one email with display names' do
19
+ mail = mail(:reply_to => 'test <test@example.com>')
20
+ message = described_class.new(location, mail)
21
+ expect(message.reply_to).to eq('test <test@example.com>')
22
+ end
23
+
24
+ it 'handles array of emails' do
25
+ mail = mail(:reply_to => ['test1@example.com', 'test2@example.com'])
26
+ message = described_class.new(location, mail)
27
+ expect(message.reply_to).to eq('test1@example.com, test2@example.com')
28
+ end
29
+
30
+ it 'handles array of emails with display names' do
31
+ mail = mail(:reply_to => ['test1 <test1@example.com>', 'test2 <test2@example.com>'])
32
+ message = described_class.new(location, mail)
33
+ expect(message.reply_to).to eq('test1 <test1@example.com>, test2 <test2@example.com>')
34
+ end
35
+
36
+ end
37
+
38
+ describe '#to' do
39
+ it 'handles one email as a string' do
40
+ mail = mail(:to => 'test@example.com')
41
+ message = described_class.new(location, mail)
42
+ expect(message.to).to eq('test@example.com')
43
+ end
44
+
45
+ it 'handles one email with display names' do
46
+ mail = mail(:to => 'test <test@example.com>')
47
+ message = described_class.new(location, mail)
48
+ expect(message.to).to eq('test <test@example.com>')
49
+ end
50
+
51
+ it 'handles array of emails' do
52
+ mail = mail(:to => ['test1@example.com', 'test2@example.com'])
53
+ message = described_class.new(location, mail)
54
+ expect(message.to).to eq('test1@example.com, test2@example.com')
55
+ end
56
+
57
+ it 'handles array of emails with display names' do
58
+ mail = mail(:to => ['test1 <test1@example.com>', 'test2 <test2@example.com>'])
59
+ message = described_class.new(location, mail)
60
+ expect(message.to).to eq('test1 <test1@example.com>, test2 <test2@example.com>')
61
+ end
62
+
63
+ end
64
+
65
+ describe '#cc' do
66
+ it 'handles one cc email as a string' do
67
+ mail = mail(:cc => 'test@example.com')
68
+ message = described_class.new(location, mail)
69
+ expect(message.cc).to eq('test@example.com')
70
+ end
71
+
72
+ it 'handles one cc email with display name' do
73
+ mail = mail(:cc => ['test <test1@example.com>', 'test2 <test2@example.com>'])
74
+ message = described_class.new(location, mail)
75
+ expect(message.cc).to eq('test <test1@example.com>, test2 <test2@example.com>')
76
+ end
77
+
78
+ it 'handles array of cc emails' do
79
+ mail = mail(:cc => ['test1@example.com', 'test2@example.com'])
80
+ message = described_class.new(location, mail)
81
+ expect(message.cc).to eq('test1@example.com, test2@example.com')
82
+ end
83
+
84
+ it 'handles array of cc emails with display names' do
85
+ mail = mail(:cc => ['test <test1@example.com>', 'test2 <test2@example.com>'])
86
+ message = described_class.new(location, mail)
87
+ expect(message.cc).to eq('test <test1@example.com>, test2 <test2@example.com>')
88
+ end
89
+
90
+ end
91
+
92
+ describe '#bcc' do
93
+ it 'handles one bcc email as a string' do
94
+ mail = mail(:bcc => 'test@example.com')
95
+ message = described_class.new(location, mail)
96
+ expect(message.bcc).to eq('test@example.com')
97
+ end
98
+
99
+ it 'handles one bcc email with display name' do
100
+ mail = mail(:bcc => ['test <test1@example.com>', 'test2 <test2@example.com>'])
101
+ message = described_class.new(location, mail)
102
+ expect(message.bcc).to eq('test <test1@example.com>, test2 <test2@example.com>')
103
+ end
104
+
105
+ it 'handles array of bcc emails' do
106
+ mail = mail(:bcc => ['test1@example.com', 'test2@example.com'])
107
+ message = described_class.new(location, mail)
108
+ expect(message.bcc).to eq('test1@example.com, test2@example.com')
109
+ end
110
+
111
+ it 'handles array of bcc emails with display names' do
112
+ mail = mail(:bcc => ['test <test1@example.com>', 'test2 <test2@example.com>'])
113
+ message = described_class.new(location, mail)
114
+ expect(message.bcc).to eq('test <test1@example.com>, test2 <test2@example.com>')
115
+ end
116
+
117
+ end
118
+
119
+ describe '#sender' do
120
+ it 'handles one email as a string' do
121
+ mail = mail(:sender => 'sender@example.com')
122
+ message = described_class.new(location, mail)
123
+ expect(message.sender).to eq('sender@example.com')
124
+ end
125
+
126
+ it 'handles one email as a string with display name' do
127
+ mail = mail(:sender => 'test <test@example.com>')
128
+ message = described_class.new(location, mail)
129
+ expect(message.sender).to eq('test <test@example.com>')
130
+ end
131
+
132
+ it 'handles array of emails' do
133
+ mail = mail(:sender => ['sender1@example.com', 'sender2@example.com'])
134
+ message = described_class.new(location, mail)
135
+ expect(message.sender).to eq('sender1@example.com, sender2@example.com')
136
+ end
137
+
138
+ it 'handles array of emails with display names' do
139
+ mail = mail(:sender => ['test <test1@example.com>', 'test2 <test2@example.com>'])
140
+ message = described_class.new(location, mail)
141
+ expect(message.sender).to eq('test <test1@example.com>, test2 <test2@example.com>')
142
+ end
143
+
144
+ end
145
+
146
+ describe '#<=>' do
147
+ it 'sorts rich type before plain type' do
148
+ plain = described_class.new(location, double(content_type: 'text/plain'))
149
+ rich = described_class.new(location, double(content_type: 'text/html'))
150
+ expect([plain, rich].sort).to eq([rich, plain])
151
+ end
152
+ end
153
+
154
+ describe '#auto_link' do
155
+ let(:message){ described_class.new(location, mail) }
156
+
157
+ it 'does not modify unlinkable text' do
158
+ text = 'the quick brown fox jumped over the lazy dog'
159
+ expect(message.auto_link(text)).to eq(text)
160
+ end
161
+
162
+ it 'adds links for http' do
163
+ raw = "Link to http://localhost:3000/example/path path"
164
+ linked = "Link to <a href=\"http://localhost:3000/example/path\">http://localhost:3000/example/path</a> path"
165
+ expect(message.auto_link(raw)).to eq(linked)
166
+ end
167
+ end
168
+
169
+ describe '#body' do
170
+ it 'handles UTF-8 charset body correctly, with QP CTE, for a non-multipart message' do
171
+ mail = mail(:sender => 'sender@example.com') do
172
+ content_type "text/html; charset=UTF-8"
173
+ content_transfer_encoding 'quoted-printable'
174
+ body "☃"
175
+ end
176
+ message = described_class.new(location, mail)
177
+ expect(message.body.encoding.name).to eq('UTF-8')
178
+ end
179
+
180
+ it 'handles UTF-8 charset HTML part body correctly, with QP CTE, for a multipart message' do
181
+ mail = mail(:sender => 'sender@example.com') do
182
+ html_part do
183
+ content_type "text/html; charset=UTF-8"
184
+ content_transfer_encoding 'quoted-printable'
185
+ body "☃"
186
+ end
187
+ end
188
+ message = described_class.new(location, mail, mail.html_part)
189
+ expect(message.body.encoding.name).to eq('UTF-8')
190
+ end
191
+
192
+ it 'handles UTF-8 charset text part body correctly, with QP CTE, for a multipart message' do
193
+ mail = mail(:sender => 'sender@example.com') do
194
+ text_part do
195
+ content_type "text/plain; charset=UTF-8"
196
+ content_transfer_encoding 'quoted-printable'
197
+ body "☃"
198
+ end
199
+ end
200
+ message = described_class.new(location, mail, mail.text_part)
201
+ expect(message.body.encoding.name).to eq('UTF-8')
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,21 @@
1
+ # Code coverage
2
+ # Travis: use code climate
3
+ # Everything else: simplecov
4
+ if ENV['RAILS_ENV'] == 'travis'
5
+ require "codeclimate-test-reporter"
6
+ CodeClimate::TestReporter.start
7
+ else
8
+ require 'simplecov'
9
+ SimpleCov.start
10
+ end
11
+
12
+ require 'rubygems'
13
+ require 'bundler/setup'
14
+ Bundler.require(:default)
15
+
16
+ require "mail"
17
+
18
+ RSpec.configure do |config|
19
+ config.treat_symbols_as_metadata_keys_with_true_values = true
20
+ config.run_all_when_everything_filtered = true
21
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kafka_mailer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Eric Hayes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: poseidon
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.7.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.7.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mail
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 2.5.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 2.5.0
97
+ description: When mail is sent from your application, kafka_mailer will put the message
98
+ contents in a kafka queue.
99
+ email: eric@deployfx.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - CHANGELOG.md
105
+ - Gemfile
106
+ - LICENSE
107
+ - README.md
108
+ - Rakefile
109
+ - lib/kafka_mailer.rb
110
+ - lib/kafka_mailer/delivery_method.rb
111
+ - lib/kafka_mailer/message.html.erb
112
+ - lib/kafka_mailer/message.rb
113
+ - lib/kafka_mailer/railtie.rb
114
+ - spec/letter_opener/delivery_method_spec.rb
115
+ - spec/letter_opener/message_spec.rb
116
+ - spec/spec_helper.rb
117
+ homepage: http://github.com/ejhayes/kafka_mailer
118
+ licenses: []
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.2.2
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Send email to apache kafka message queue.
140
+ test_files: []