mail_builder19 1.0-java
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/Doubleshot +19 -0
- data/MIT-LICENSE +19 -0
- data/README.md +56 -0
- data/lib/mail_builder.rb +317 -0
- data/lib/mail_builder/attachment.rb +35 -0
- data/test/helper.rb +30 -0
- data/test/mail_builder_spec.rb +50 -0
- metadata +102 -0
data/Doubleshot
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
Doubleshot.new do |config|
|
4
|
+
config.project = "mail_builder19"
|
5
|
+
config.version = "1.0"
|
6
|
+
|
7
|
+
config.gem "mime-types"
|
8
|
+
|
9
|
+
config.gemspec do |spec|
|
10
|
+
spec.summary = "MailBuilder is a simple library for building RFC compliant MIME emails."
|
11
|
+
spec.description = <<-DESCRIPTION
|
12
|
+
MailBuilder is a simple library for building RFC compliant MIME emails.
|
13
|
+
DESCRIPTION
|
14
|
+
spec.homepage = "https://github.com/sam/mail_builder"
|
15
|
+
spec.authors = [ "Bernerd Schaefer", "Sam Smoot" ]
|
16
|
+
spec.email = "ssmoot@gmail.com"
|
17
|
+
spec.license = "MIT-LICENSE"
|
18
|
+
end
|
19
|
+
end
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2009 Bernerd J. Schaefer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# MailBuilder
|
2
|
+
|
3
|
+
[](http://travis-ci.org/sam/mail_builder)
|
4
|
+
|
5
|
+
MailBuilder is a library for building RFC compliant MIME messages,
|
6
|
+
with support for text and HTML emails, as well as attachments.
|
7
|
+
|
8
|
+
## Basic Usage
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
require 'rubygems'
|
12
|
+
require 'mail_builder'
|
13
|
+
|
14
|
+
mail = MailBuilder.new
|
15
|
+
mail.to = "joe@example.com"
|
16
|
+
mail.text = "Body"
|
17
|
+
|
18
|
+
sendmail = IO.popen("#{`which sendmail`.chomp} -i -t", "w+")
|
19
|
+
sendmail.puts mail
|
20
|
+
sendmail.close
|
21
|
+
```
|
22
|
+
|
23
|
+
#### or
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require 'net/smtp'
|
27
|
+
|
28
|
+
Net::SMTP.start("smtp.address.com", 25) do |smtp|
|
29
|
+
smtp.send_message(mail.to_s, mail.from, mail.to)
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
## Advantages
|
34
|
+
|
35
|
+
One of the key advantages to using MailBuilder over other libraries
|
36
|
+
(such as MailFactory) is that costly operations - generating boundaries,
|
37
|
+
reading attached files, etc. - are delayed until the physical message
|
38
|
+
is built (by calling `build` or `to_s`).
|
39
|
+
|
40
|
+
This gives you the freedom to generate many thousands of emails
|
41
|
+
with almost no time-cost. The emails could then be passed to some
|
42
|
+
external system - DRb, database - for final delivery.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
10_000.times do
|
46
|
+
mail = MailBuilder.new('to' => 'joe@example.com')
|
47
|
+
mail.html = View.new("mailers/large_mailer")
|
48
|
+
mail.attach("large_file.pdf")
|
49
|
+
|
50
|
+
ExternalMailServer.send!(mail)
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
The external process would then build the email, at which point the
|
55
|
+
view would be rendered and attachments read, while the local process
|
56
|
+
would complete in very little (on my machine, sub-second) time.
|
data/lib/mail_builder.rb
ADDED
@@ -0,0 +1,317 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "java"
|
4
|
+
require "pathname"
|
5
|
+
require "time"
|
6
|
+
|
7
|
+
require "rubygems"
|
8
|
+
require "mime/types"
|
9
|
+
|
10
|
+
##
|
11
|
+
# MailBuilder is a library for building RFC compliant MIME messages,
|
12
|
+
# with support for text and HTML emails, as well as attachments.
|
13
|
+
#
|
14
|
+
# Basic Usage:
|
15
|
+
#
|
16
|
+
# mail = MailBuilder.new
|
17
|
+
# mail.to = "joe@example.com"
|
18
|
+
# mail.text = "Body"
|
19
|
+
#
|
20
|
+
# sendmail = IO.popen("#{`which sendmail`.chomp} -i -t", "w+")
|
21
|
+
# sendmail.puts mail
|
22
|
+
# sendmail.close
|
23
|
+
#
|
24
|
+
# # or
|
25
|
+
#
|
26
|
+
# require 'net/smtp'
|
27
|
+
#
|
28
|
+
# Net::SMTP.start("smtp.address.com", 25) do |smtp|
|
29
|
+
# smtp.send_message(mail.to_s, mail.from, mail.to)
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
##
|
33
|
+
class MailBuilder
|
34
|
+
require Pathname(__FILE__).dirname + "mail_builder/attachment"
|
35
|
+
|
36
|
+
##
|
37
|
+
# Boundary characters, slightly adapted from those allowed by rfc1341,
|
38
|
+
# representing:
|
39
|
+
#
|
40
|
+
# ALPHA / DIGIT / "'" / "(" / ")" / "*" / "," / "-" / "." / "/" / ":"
|
41
|
+
#
|
42
|
+
# See 7.2.1, http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
|
43
|
+
##
|
44
|
+
BOUNDARY_CHARS = ((39..58).to_a + (65..90).to_a + (97..122).to_a).map { |_| _.chr }.freeze
|
45
|
+
|
46
|
+
CHARSET = 'utf-8'.freeze
|
47
|
+
|
48
|
+
##
|
49
|
+
# Printable characters which RFC 2047 says must be escaped.
|
50
|
+
##
|
51
|
+
RFC2047_REPLACEMENTS = [
|
52
|
+
['?', '=%X' % ??.ord],
|
53
|
+
['_', '=%X' % ?_.ord],
|
54
|
+
[' ', '_'],
|
55
|
+
[/=$/, '']
|
56
|
+
].freeze
|
57
|
+
|
58
|
+
attr_accessor :html, :text
|
59
|
+
attr_reader :headers, :attachments
|
60
|
+
|
61
|
+
##
|
62
|
+
# Accepts an options hash, setting text and html if provided, and
|
63
|
+
# setting any provided headers.
|
64
|
+
#
|
65
|
+
# mailer = MailBuilder.new(:text => "Text", :to => "admin@site.com", "X-Priority" => 1)
|
66
|
+
# mailer.text # => "Text"
|
67
|
+
# mailer.to # => "admin@site.com"
|
68
|
+
# mailer.get_header("X-Priority") # => 1
|
69
|
+
##
|
70
|
+
def initialize(options = {})
|
71
|
+
@headers = []
|
72
|
+
@attachments = []
|
73
|
+
@text = nil
|
74
|
+
@html = nil
|
75
|
+
|
76
|
+
parse_options(options)
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Adds a header value to the mailer's headers, without removing
|
81
|
+
# previous values.
|
82
|
+
#
|
83
|
+
# mailer.add_header("From", "admin@example.com")
|
84
|
+
# mailer.add_header("From", "john@example.com")
|
85
|
+
#
|
86
|
+
# mailer.headers # => [["From", "admin@example.com"], ["From", "admin@example.com"]]
|
87
|
+
##
|
88
|
+
def add_header(key, value)
|
89
|
+
@headers << [key.to_s, value]
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Retrieves a value from the mailer's headers.
|
94
|
+
#
|
95
|
+
# mailer.get_header("to") # => "admin@example.com"
|
96
|
+
##
|
97
|
+
def get_header(key)
|
98
|
+
@headers.detect { |k, v| return v if k == key }
|
99
|
+
end
|
100
|
+
alias [] get_header
|
101
|
+
|
102
|
+
def remove_header(key)
|
103
|
+
@headers.reject! { |k,| k == key }
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Adds a header value to the mailer's headers, replacing previous values.
|
108
|
+
#
|
109
|
+
# mailer.add_header("From", "admin@example.com")
|
110
|
+
# mailer.set_header("From", "john@example.com")
|
111
|
+
#
|
112
|
+
# mailer.headers # => [["From", "admin@example.com"]]
|
113
|
+
##
|
114
|
+
def set_header(key, value)
|
115
|
+
remove_header(key)
|
116
|
+
add_header(key, value)
|
117
|
+
end
|
118
|
+
alias []= set_header
|
119
|
+
|
120
|
+
##
|
121
|
+
# Returns the envelope id for this mailer. The mail spec's ENV_ID is
|
122
|
+
# used to provide a unique identifier that follows an email through it's
|
123
|
+
# various states -- including bounces -- allowing it to be tracked.
|
124
|
+
##
|
125
|
+
def envelope_id
|
126
|
+
@envelope_id ||= java.util.UUID.random_uuid.to_s
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# We define getters and setters for commonly used headers.
|
131
|
+
##
|
132
|
+
%w(from to cc bcc reply_to subject).each do |header|
|
133
|
+
define_method(header) do
|
134
|
+
get_header(header)
|
135
|
+
end
|
136
|
+
|
137
|
+
define_method(header + "=") do |value|
|
138
|
+
set_header(header, value)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# Wrapper for attach_as, setting the attachment filename to the file's
|
144
|
+
# basename.
|
145
|
+
#
|
146
|
+
# mailer.attach "some/file.pdf"
|
147
|
+
##
|
148
|
+
def attach(file, type = nil, headers = nil)
|
149
|
+
file = Pathname(file)
|
150
|
+
|
151
|
+
attach_as(file, file.basename, type, headers)
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Adds an Attachment to the email.
|
156
|
+
#
|
157
|
+
# If file is an IO or File object, it's contents will be read immediately, in case
|
158
|
+
# the mail will be delivered to an external service without access to the object.
|
159
|
+
# Otherwise, the attached file's content will be read when the message is built.
|
160
|
+
#
|
161
|
+
# If no type is provided, the MIME::Types library will be used to find a suitable
|
162
|
+
# content type.
|
163
|
+
#
|
164
|
+
# mailer.attach "account.html"
|
165
|
+
# mailer.attach_as StringIO.new("test"), "account.txt"
|
166
|
+
#
|
167
|
+
##
|
168
|
+
def attach_as(file, name, type = nil, headers = nil)
|
169
|
+
@attachments << Attachment.new(file, name, type, headers)
|
170
|
+
end
|
171
|
+
|
172
|
+
def multipart?
|
173
|
+
attachments? || @html
|
174
|
+
end
|
175
|
+
|
176
|
+
def attachments?
|
177
|
+
@attachments.any?
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Builds the full email message suitable to be passed to Sendmail, Net::SMTP, etc.
|
182
|
+
#
|
183
|
+
# It sets the Mail-From header (used for tracking emails), date, and message id,
|
184
|
+
# and then assembles the headers, body, and attachments.
|
185
|
+
#
|
186
|
+
# All expensive operations -- generating boundaries, rendering views, reading
|
187
|
+
# attached files -- are delayed until this method is called.
|
188
|
+
##
|
189
|
+
def build
|
190
|
+
set_header("Mail-From", "#{ENV["USER"]}@localhost ENVID=#{envelope_id}")
|
191
|
+
set_header("Date", Time.now.rfc2822)
|
192
|
+
set_header("Message-ID", "<#{Time.now.to_f}.#{Process.pid}@#{get_header("from").to_s.split("@", 2)[1]}>")
|
193
|
+
|
194
|
+
if multipart?
|
195
|
+
set_header("Mime-Version", "1.0")
|
196
|
+
if attachments?
|
197
|
+
set_header("Content-Type", "multipart/mixed; boundary=\"#{attachment_boundary}\"")
|
198
|
+
else
|
199
|
+
set_header("Content-Type", "multipart/alternative; boundary=\"#{body_boundary}\"")
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
build_headers + build_body
|
204
|
+
end
|
205
|
+
alias to_s build
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
def build_headers
|
210
|
+
@headers.map do |header, value|
|
211
|
+
header = header.gsub("_", "-")
|
212
|
+
key = header.downcase
|
213
|
+
|
214
|
+
value = quote(value, 'rfc2047') if key == "subject"
|
215
|
+
value = quote_address(value) if %w(from to cc bcc reply-to).include?(key)
|
216
|
+
|
217
|
+
"#{header}: #{value}"
|
218
|
+
end.join("\r\n") + "\r\n\r\n"
|
219
|
+
end
|
220
|
+
|
221
|
+
def build_body
|
222
|
+
return @text.to_s unless multipart?
|
223
|
+
|
224
|
+
body = []
|
225
|
+
body << "This is a multi-part message in MIME format."
|
226
|
+
body << "--#{attachment_boundary}\r\nContent-Type: multipart/alternative; boundary=\"#{body_boundary}\""
|
227
|
+
|
228
|
+
body << build_body_boundary('text/plain')
|
229
|
+
body << quote(@text)
|
230
|
+
|
231
|
+
body << build_body_boundary('text/html')
|
232
|
+
body << quote(@html)
|
233
|
+
|
234
|
+
body << "--#{body_boundary}--"
|
235
|
+
|
236
|
+
if attachments?
|
237
|
+
@attachments.each do |attachment|
|
238
|
+
body << build_attachment_boundary(attachment)
|
239
|
+
body << attachment
|
240
|
+
body << "\r\n--#{attachment_boundary}--"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
body.join("\r\n\r\n")
|
245
|
+
end
|
246
|
+
|
247
|
+
def build_body_boundary(type)
|
248
|
+
boundary = []
|
249
|
+
boundary << "--#{body_boundary}"
|
250
|
+
boundary << "Content-Type: #{type}; charset=#{CHARSET}#{'; format=flowed' if type == 'text/plain'}"
|
251
|
+
boundary << "Content-Transfer-Encoding: quoted-printable"
|
252
|
+
boundary.join("\r\n")
|
253
|
+
end
|
254
|
+
|
255
|
+
def build_attachment_boundary(attachment)
|
256
|
+
boundary = []
|
257
|
+
boundary << "--#{attachment_boundary}"
|
258
|
+
boundary << "Content-Type: #{attachment.type}; name=\"#{attachment.name}\""
|
259
|
+
boundary << "Content-Transfer-Encoding: base64"
|
260
|
+
boundary << "Content-Disposition: inline; filename=\"#{attachment.name}\""
|
261
|
+
|
262
|
+
boundary.push(*attachment.headers) if attachment.headers
|
263
|
+
|
264
|
+
boundary.join("\r\n")
|
265
|
+
end
|
266
|
+
|
267
|
+
def generate_boundary
|
268
|
+
"----=_NextPart_" + (1..25).map { BOUNDARY_CHARS[rand(BOUNDARY_CHARS.size)] }.join
|
269
|
+
end
|
270
|
+
|
271
|
+
def attachment_boundary
|
272
|
+
@attachment_boundary ||= generate_boundary
|
273
|
+
end
|
274
|
+
|
275
|
+
def body_boundary
|
276
|
+
@body_boundary ||= generate_boundary
|
277
|
+
end
|
278
|
+
|
279
|
+
def parse_options(options)
|
280
|
+
options.each do |key, value|
|
281
|
+
case key
|
282
|
+
when :html
|
283
|
+
self.html = value
|
284
|
+
when :text
|
285
|
+
self.text = text
|
286
|
+
else
|
287
|
+
set_header(key, value)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def quote(text, method = 'rfc2045')
|
293
|
+
return unless text
|
294
|
+
|
295
|
+
self.send("#{method}_encode", text)
|
296
|
+
end
|
297
|
+
|
298
|
+
def quote_address(address)
|
299
|
+
return address.map { |a| quote_address(a) }.join(", ") if address.is_a?(Array)
|
300
|
+
|
301
|
+
address.gsub(/['"](.+?)['"]\s+(<.+?>)/) do
|
302
|
+
"\"#{quote($1, 'rfc2047')}\" #{$2}"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def rfc2047_encode(text)
|
307
|
+
text = text.enum_for(:each_byte).map { |ord| ord < 128 && ord != ?=.ord ? ord.chr : "=%X" % ord }.join.chomp
|
308
|
+
|
309
|
+
RFC2047_REPLACEMENTS.each { |replacement| text.gsub!(*replacement) }
|
310
|
+
|
311
|
+
"=?#{CHARSET}?Q?#{text}?="
|
312
|
+
end
|
313
|
+
|
314
|
+
def rfc2045_encode(text)
|
315
|
+
[text].pack('M').gsub("\n", "\r\n").chomp("=\r\n")
|
316
|
+
end
|
317
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class MailBuilder
|
2
|
+
class Attachment
|
3
|
+
|
4
|
+
attr_accessor :file, :name, :type, :headers
|
5
|
+
|
6
|
+
def initialize(file, name, type, headers)
|
7
|
+
@file = file
|
8
|
+
@name = name
|
9
|
+
@type = type
|
10
|
+
@headers = headers
|
11
|
+
|
12
|
+
# If we have a File/IO object, read it. Otherwise, we'll read it lazily.
|
13
|
+
@body = file.read() if !file.kind_of?(Pathname) && file.respond_to?(:read)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
@body ||= File.open(file.to_s(), "rb") { |f| f.read() }
|
18
|
+
|
19
|
+
[@body].pack("m")
|
20
|
+
end
|
21
|
+
|
22
|
+
def name
|
23
|
+
@name
|
24
|
+
end
|
25
|
+
|
26
|
+
def type
|
27
|
+
@type ||= MIME::Types.type_for(@name.to_s).to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
"#<MailBuilder::Attachment @file=#{@file.inspect}> @name=#{@name.inspect} @type=#{@type.inspect} @headers=#{@headers.inspect}"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "doubleshot/setup"
|
2
|
+
|
3
|
+
require "minitest/autorun"
|
4
|
+
require "minitest/pride"
|
5
|
+
require "minitest/wscolor"
|
6
|
+
|
7
|
+
require Pathname(__FILE__).dirname.parent + "lib/mail_builder"
|
8
|
+
|
9
|
+
(MailBuilder.private_instance_methods - Object.private_instance_methods).each do |method|
|
10
|
+
MailBuilder.send(:public, method)
|
11
|
+
end
|
12
|
+
|
13
|
+
def mailer(options = {})
|
14
|
+
MailBuilder.new(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
module MiniTest
|
18
|
+
module Assertions
|
19
|
+
def assert_nothing_raised *args
|
20
|
+
yield
|
21
|
+
assert true, "Nothing raised"
|
22
|
+
rescue Exception => e
|
23
|
+
fail "Expected nothing raised, but got #{e.class}: #{e.message}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Expectations
|
28
|
+
infect_an_assertion :assert_nothing_raised, :wont_raise
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
|
3
|
+
# encoding: UTF-8
|
4
|
+
|
5
|
+
require File.dirname(__FILE__) + '/helper'
|
6
|
+
|
7
|
+
describe MailBuilder do
|
8
|
+
|
9
|
+
it "must encode recipients properly" do
|
10
|
+
mailer(:to => "bernerd@wieck.com").build_headers.strip
|
11
|
+
.must_equal "to: bernerd@wieck.com"
|
12
|
+
|
13
|
+
mailer(:to => '"Bernerd" <bernerd@wieck.com>').build_headers.strip
|
14
|
+
.must_equal "to: \"=?utf-8?Q?Bernerd?=\" <bernerd@wieck.com>"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "must encode multiple recipients properly" do
|
18
|
+
desired_to = 'to: "=?utf-8?Q?Bernerd?=" <bernerd@wieck.com>, "=?utf-8?Q?Adam?=" <adam@wieck.com>'
|
19
|
+
|
20
|
+
mailer(:to => '"Bernerd" <bernerd@wieck.com>, "Adam" <adam@wieck.com>')
|
21
|
+
.build_headers.strip.must_equal desired_to
|
22
|
+
mailer(:to => ['"Bernerd" <bernerd@wieck.com>', '"Adam" <adam@wieck.com>'])
|
23
|
+
.build_headers.strip.must_equal desired_to
|
24
|
+
end
|
25
|
+
|
26
|
+
it "must encode all addresses" do
|
27
|
+
[ "from", "to", "cc", "bcc", "reply-to" ].each do |field|
|
28
|
+
mailer(field => '"Bernerd" <bernerd@wieck.com>').build_headers.strip
|
29
|
+
.must_equal "#{field}: \"=?utf-8?Q?Bernerd?=\" <bernerd@wieck.com>"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must rfc2045 encode properly" do
|
34
|
+
mailer.rfc2045_encode('<a href="http://google.com">Google</a>')
|
35
|
+
.must_equal '<a href=3D"http://google.com">Google</a>'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "must rfc2047 encode properly" do
|
39
|
+
mailer.rfc2047_encode("This + is = a _ test * subject")
|
40
|
+
.must_equal "=?utf-8?Q?This_+_is_=3D_a_=5F_test_*_subject?="
|
41
|
+
|
42
|
+
mailer.rfc2047_encode("\303\244\303\244\303\244\303\266\303\266\303\266")
|
43
|
+
.must_equal "=?utf-8?Q?=C3=A4=C3=A4=C3=A4=C3=B6=C3=B6=C3=B6?="
|
44
|
+
end
|
45
|
+
|
46
|
+
it "mailer must not error on build if empty" do
|
47
|
+
-> { mailer.to_s }.wont_raise
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mail_builder19
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
prerelease:
|
6
|
+
platform: java
|
7
|
+
authors:
|
8
|
+
- Bernerd Schaefer
|
9
|
+
- Sam Smoot
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-12-05 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: mime-types
|
17
|
+
version_requirements: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: !binary |-
|
22
|
+
MA==
|
23
|
+
none: false
|
24
|
+
requirement: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ! '>='
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: !binary |-
|
29
|
+
MA==
|
30
|
+
none: false
|
31
|
+
prerelease: false
|
32
|
+
type: :runtime
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: doubleshot
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: !binary |-
|
40
|
+
MA==
|
41
|
+
none: false
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: !binary |-
|
47
|
+
MA==
|
48
|
+
none: false
|
49
|
+
prerelease: false
|
50
|
+
type: :development
|
51
|
+
description: |
|
52
|
+
MailBuilder is a simple library for building RFC compliant MIME emails.
|
53
|
+
email: ssmoot@gmail.com
|
54
|
+
executables: []
|
55
|
+
extensions: []
|
56
|
+
extra_rdoc_files: []
|
57
|
+
files:
|
58
|
+
- test/helper.rb
|
59
|
+
- test/mail_builder_spec.rb
|
60
|
+
- Doubleshot
|
61
|
+
- MIT-LICENSE
|
62
|
+
- README.md
|
63
|
+
- lib/mail_builder/attachment.rb
|
64
|
+
- lib/mail_builder.rb
|
65
|
+
homepage: https://github.com/sam/mail_builder
|
66
|
+
licenses:
|
67
|
+
- MIT-LICENSE
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options:
|
70
|
+
- --line-numbers
|
71
|
+
- --main
|
72
|
+
- README.textile
|
73
|
+
- --title
|
74
|
+
- mail_builder19 Documentation
|
75
|
+
- lib
|
76
|
+
- README.textile
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
- target
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: !binary |-
|
85
|
+
MA==
|
86
|
+
none: false
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: !binary |-
|
92
|
+
MA==
|
93
|
+
none: false
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 1.8.24
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: MailBuilder is a simple library for building RFC compliant MIME emails.
|
100
|
+
test_files:
|
101
|
+
- test/helper.rb
|
102
|
+
- test/mail_builder_spec.rb
|