kuvert 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c8954c2b806b2e4ecdea6b2b3e897e618424c756
4
+ data.tar.gz: e06e1405adf0777d7ea12e6be06ced1fbacd6a38
5
+ SHA512:
6
+ metadata.gz: da810f127283d91127053e78c6a2edff3d7b273c8613ae431519ef350241a9303112cdbc0ad4418a918fa9be5b06949cd267e0ea2a54b45763c9148cccf3a298
7
+ data.tar.gz: 6f8f63c165c89c8bd959cff74be1154a129b27d7e87f88146f575d4df4ea556fca3173d081036d8ea7e593a8603cbeee928e1406381b4c529d063577042bc9fc
data/.gems ADDED
@@ -0,0 +1 @@
1
+ mime-types -v 2.4.3
data/Makefile ADDED
@@ -0,0 +1,4 @@
1
+ test: .PHONY
2
+ ruby test/kuvert_test.rb
3
+
4
+ .PHONY:
data/README.markdown ADDED
@@ -0,0 +1,28 @@
1
+ kuvert
2
+ ======
3
+
4
+ Continuing the legacy of [MailFactory][1].
5
+
6
+ ## Usage
7
+
8
+ ```ruby
9
+ mail = Kuvert.new
10
+ mail.to = 'dst@mailinator.com'
11
+ mail.from = 'src@mailinator.com'
12
+ mail.subject = 'hello'
13
+ mail.text = 'wonderful day to you!'
14
+ mail.attach('/path/to/your.pdf')
15
+ mail.to_s
16
+ ```
17
+
18
+ ## Credit
19
+
20
+ All of the credit goes to David Powers for his original
21
+ work on [MailFactory][1].
22
+
23
+ ## License
24
+
25
+ [Ruby License][2]
26
+
27
+ [1]: http://rubygems.org/gems/mailfactory
28
+ [2]: https://www.ruby-lang.org/en/about/license.txt
data/kuvert.gemspec ADDED
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "kuvert"
3
+ s.version = "0.0.1"
4
+ s.summary = %{Continuing the MailFactory legacy}
5
+ s.description = %{Keep MailFactory updated with the times}
6
+ s.authors = ["David Powers", "Cyril David"]
7
+ s.email = ["cyx@cyx.is"]
8
+ s.homepage = "http://github.com/cyx/kuvert"
9
+ s.license = "MIT"
10
+
11
+ s.files = `git ls-files`.split("\n")
12
+
13
+ s.add_dependency "mime-types", "~> 2.4"
14
+ end
data/lib/kuvert.rb ADDED
@@ -0,0 +1,439 @@
1
+ # = Overview:
2
+ # A simple to use module for generating RFC compliant MIME mail
3
+ # ---
4
+ # = License:
5
+ # Author:: David Powers
6
+ # Contributors: Cyril David
7
+ # Copyright:: May, 2005
8
+ # License:: Ruby License
9
+ # ---
10
+ # = Usage:
11
+ # require 'net/smtp'
12
+ # require 'rubygems'
13
+ # require 'mailfactory'
14
+ #
15
+ #
16
+ # mail = Kuvert.new()
17
+ # mail.to = "test@test.com"
18
+ # mail.from = "sender@sender.com"
19
+ # mail.subject = "Here are some files for you!"
20
+ # mail.text = "This is what people with plain text mail readers will see"
21
+ # mail.html = "A little something <b>special</b> for people with HTML readers"
22
+ # mail.attach("/etc/fstab")
23
+ # mail.attach("/some/other/file")
24
+ #
25
+ # Net::SMTP.start('smtp1.testmailer.com', 25, 'mail.from.domain', fromaddress, password, :cram_md5) { |smtp|
26
+ # mail.to = toaddress
27
+ # smtp.send_message(mail.to_s(), fromaddress, toaddress)
28
+ # }
29
+
30
+ require 'pathname'
31
+ require 'mime/types'
32
+
33
+ # An easy class for creating a mail message
34
+ class Kuvert
35
+
36
+ VERSION = '1.4.0'
37
+
38
+ attr :bcc
39
+
40
+ def initialize()
41
+ @headers = Array.new()
42
+ @attachments = Array.new()
43
+ @attachmentboundary = generate_boundary()
44
+ @bodyboundary = generate_boundary()
45
+ @html = nil
46
+ @text = nil
47
+ @charset = 'utf-8'
48
+ @bcc = []
49
+ end
50
+
51
+ # adds a header to the bottom of the headers
52
+ def add_header(header, value)
53
+ value = quoted_printable_with_instruction(value, @charset) if header == 'subject'
54
+ value = quote_address_if_necessary(value, @charset) if %w[from to cc bcc reply-to].include?(header.downcase)
55
+ @headers << "#{header}: #{value}"
56
+ end
57
+
58
+ # removes the named header - case insensitive
59
+ def remove_header(header)
60
+ @headers.each_index() { |i|
61
+ if(@headers[i] =~ /^#{Regexp.escape(header)}:/i)
62
+ @headers.delete_at(i)
63
+ end
64
+ }
65
+ end
66
+
67
+ # sets a header (removing any other versions of that header)
68
+ def set_header(header, value)
69
+ remove_header(header)
70
+ add_header(header, value)
71
+ end
72
+
73
+ def replyto=(newreplyto)
74
+ remove_header("Reply-To")
75
+ add_header("Reply-To", newreplyto)
76
+ end
77
+
78
+ def replyto()
79
+ return(get_header("Reply-To")[0])
80
+ end
81
+
82
+ def bcc=(bcc)
83
+ @bcc.push(bcc)
84
+ end
85
+
86
+ def recipients
87
+ [].tap do |ret|
88
+ ret.push(*to)
89
+ ret.push(*cc)
90
+ ret.push(*bcc)
91
+ end
92
+ end
93
+
94
+ # sets the plain text body of the message
95
+ def text=(newtext)
96
+ @text = newtext
97
+ end
98
+
99
+ # sets the HTML body of the message. Only the body of the
100
+ # html should be provided
101
+ def html=(newhtml)
102
+ @html = "<html>\n<head>\n<meta content=\"text/html;charset=#{@charset}\" http-equiv=\"Content-Type\">\n</head>\n<body bgcolor=\"#ffffff\" text=\"#000000\">\n#{newhtml}\n</body>\n</html>"
103
+ end
104
+
105
+ # sets the HTML body of the message. The entire HTML section should be provided
106
+ def rawhtml=(newhtml)
107
+ @html = newhtml
108
+ end
109
+
110
+ # implement method missing to provide helper methods for setting and getting headers.
111
+ # Headers with '-' characters may be set/gotten as 'x_mailer' or 'XMailer' (splitting
112
+ # will occur between capital letters or on '_' chracters)
113
+ def method_missing(methId, *args)
114
+ name = methId.id2name()
115
+
116
+ # mangle the name if we have to
117
+ if(name =~ /_/)
118
+ name = name.gsub(/_/, '-')
119
+ elsif(name =~ /[A-Z]/)
120
+ name = name.gsub(/([a-zA-Z])([A-Z])/, '\1-\2')
121
+ end
122
+
123
+ # determine if it sets or gets, and do the right thing
124
+ if(name =~ /=$/)
125
+ if(args.length != 1)
126
+ super(methId, args)
127
+ end
128
+ set_header(name[/^(.*)=$/, 1], args[0])
129
+ else
130
+ if(args.length != 0)
131
+ super(methId, args)
132
+ end
133
+ headers = get_header(name)
134
+ return(get_header(name))
135
+ end
136
+ end
137
+
138
+ # returns the value (or values) of the named header in an array
139
+ def get_header(header)
140
+ headers = Array.new()
141
+ headerregex = /^#{Regexp.escape(header)}:/i
142
+ @headers.each() { |h|
143
+ if(headerregex.match(h))
144
+ headers << h[/^[^:]+:(.*)/i, 1].strip()
145
+ end
146
+ }
147
+
148
+ return(headers)
149
+ end
150
+
151
+ # returns true if the email is multipart
152
+ def multipart?()
153
+ if(@attachments.length > 0 or @html != nil)
154
+ return(true)
155
+ else
156
+ return(false)
157
+ end
158
+ end
159
+
160
+ # builds an email and returns it as a string. Takes the following options:
161
+ # <tt>:messageid</tt>:: Adds a message id to the message based on the from header (defaults to false)
162
+ # <tt>:date</tt>:: Adds a date to the message if one is not present (defaults to true)
163
+ def construct(options = Hash.new)
164
+ if(options[:date] == nil)
165
+ options[:date] = true
166
+ end
167
+
168
+ if(options[:messageid])
169
+ # add a unique message-id
170
+ remove_header("Message-ID")
171
+ sendingdomain = get_header('from')[0].to_s()[/@([-a-zA-Z0-9._]+)/,1].to_s()
172
+ add_header("Message-ID", "<#{Time.now.to_f()}.#{Process.euid()}.#{String.new.object_id()}@#{sendingdomain}>")
173
+ end
174
+
175
+ if(options[:date])
176
+ if(get_header("Date").length == 0)
177
+ add_header("Date", Time.now.strftime("%a, %d %b %Y %H:%M:%S %z"))
178
+ end
179
+ end
180
+
181
+ # Add a mime header if we don't already have one and we have multiple parts
182
+ if(multipart?())
183
+ if(get_header("MIME-Version").length == 0)
184
+ add_header("MIME-Version", "1.0")
185
+ end
186
+
187
+ if(get_header("Content-Type").length == 0)
188
+ if(@attachments.length == 0)
189
+ add_header("Content-Type", "multipart/alternative;boundary=\"#{@bodyboundary}\"")
190
+ else
191
+ add_header("Content-Type", "multipart/mixed; boundary=\"#{@attachmentboundary}\"")
192
+ end
193
+ end
194
+ end
195
+
196
+ return("#{headers_to_s()}#{body_to_s()}")
197
+ end
198
+
199
+ # returns a formatted email - equivalent to construct(:messageid => true)
200
+ def to_s()
201
+ return(construct(:messageid => true))
202
+ end
203
+
204
+ # generates a unique boundary string
205
+ def generate_boundary()
206
+ randomstring = Array.new()
207
+ 1.upto(25) {
208
+ whichglyph = rand(100)
209
+ if(whichglyph < 40)
210
+ randomstring << (rand(25) + 65).chr()
211
+ elsif(whichglyph < 70)
212
+ randomstring << (rand(25) + 97).chr()
213
+ elsif(whichglyph < 90)
214
+ randomstring << (rand(10) + 48).chr()
215
+ elsif(whichglyph < 95)
216
+ randomstring << '.'
217
+ else
218
+ randomstring << '_'
219
+ end
220
+ }
221
+ return("----=_NextPart_#{randomstring.join()}")
222
+ end
223
+
224
+ # adds an attachment to the mail. Type may be given as a mime type. If it
225
+ # is left off and the MIME::Types module is available it will be determined automagically.
226
+ # If the optional attachemntheaders is given, then they will be added to the attachment
227
+ # boundary in the email, which can be used to produce Content-ID markers. attachmentheaders
228
+ # can be given as an Array or a String.
229
+ def add_attachment(filename, type=nil, attachmentheaders = nil)
230
+ attachment = Hash.new()
231
+ attachment['filename'] = Pathname.new(filename).basename
232
+ if(type == nil)
233
+ attachment['mimetype'] = MIME::Types.of(filename).first.to_s
234
+ else
235
+ attachment['mimetype'] = type
236
+ end
237
+
238
+ # Open in rb mode to handle Windows, which mangles binary files opened in a text mode
239
+ File.open(filename, "rb") { |fp|
240
+ attachment['attachment'] = file_encode(fp.read())
241
+ }
242
+
243
+ if(attachmentheaders != nil)
244
+ if(!attachmentheaders.kind_of?(Array))
245
+ attachmentheaders = attachmentheaders.split(/\r?\n/)
246
+ end
247
+ attachment['headers'] = attachmentheaders
248
+ end
249
+
250
+ @attachments << attachment
251
+ end
252
+
253
+ # adds an attachment to the mail as emailfilename. Type may be given as a mime type. If it
254
+ # is left off and the MIME::Types module is available it will be determined automagically.
255
+ # file may be given as an IO stream (which will be read until the end) or as a filename.
256
+ # If the optional attachemntheaders is given, then they will be added to the attachment
257
+ # boundary in the email, which can be used to produce Content-ID markers. attachmentheaders
258
+ # can be given as an Array of a String.
259
+ def add_attachment_as(file, emailfilename, type=nil, attachmentheaders = nil)
260
+ attachment = Hash.new()
261
+ attachment['filename'] = emailfilename
262
+
263
+ if(type != nil)
264
+ attachment['mimetype'] = type.to_s()
265
+ elsif(file.kind_of?(String) or file.kind_of?(Pathname))
266
+ attachment['mimetype'] = MIME::Types.of(file.to_s()).first.to_s
267
+ else
268
+ attachment['mimetype'] = ''
269
+ end
270
+
271
+ if(file.kind_of?(String) or file.kind_of?(Pathname))
272
+ # Open in rb mode to handle Windows, which mangles binary files opened in a text mode
273
+ File.open(file.to_s(), "rb") { |fp|
274
+ attachment['attachment'] = file_encode(fp.read())
275
+ }
276
+ elsif(file.respond_to?(:read))
277
+ attachment['attachment'] = file_encode(file.read())
278
+ else
279
+ raise(Exception, "file is not a supported type (must be a String, Pathnamem, or support read method)")
280
+ end
281
+
282
+ if(attachmentheaders != nil)
283
+ if(!attachmentheaders.kind_of?(Array))
284
+ attachmentheaders = attachmentheaders.split(/\r?\n/)
285
+ end
286
+ attachment['headers'] = attachmentheaders
287
+ end
288
+
289
+ @attachments << attachment
290
+ end
291
+
292
+ alias attach add_attachment
293
+ alias attach_as add_attachment_as
294
+
295
+ protected
296
+
297
+ # returns the @headers as a properly formatted string
298
+ def headers_to_s()
299
+ return("#{@headers.join("\r\n")}\r\n\r\n")
300
+ end
301
+
302
+ # returns the body as a properly formatted string
303
+ def body_to_s()
304
+ body = Array.new()
305
+
306
+ # simple message with one part
307
+ if(!multipart?())
308
+ return(@text)
309
+ else
310
+ body << "This is a multi-part message in MIME format.\r\n\r\n--#{@attachmentboundary}\r\nContent-Type: multipart/alternative; boundary=\"#{@bodyboundary}\""
311
+
312
+ if(@attachments.length > 0)
313
+ # text part
314
+ body << "#{buildbodyboundary("text/plain; charset=#{@charset}; format=flowed", 'quoted-printable')}\r\n\r\n#{quote_if_necessary(@text, @charset)}"
315
+
316
+ # html part if one is provided
317
+ if @html
318
+ body << "#{buildbodyboundary("text/html; charset=#{@charset}", 'quoted-printable')}\r\n\r\n#{quote_if_necessary(@html, @charset)}"
319
+ end
320
+
321
+ body << "--#{@bodyboundary}--"
322
+
323
+ # and, the attachments
324
+ if(@attachments.length > 0)
325
+ @attachments.each() { |attachment|
326
+ body << "#{buildattachmentboundary(attachment)}\r\n\r\n#{attachment['attachment']}"
327
+ }
328
+ body << "\r\n--#{@attachmentboundary}--"
329
+ end
330
+ else
331
+ # text part
332
+ body << "#{buildbodyboundary("text/plain; charset=#{@charset}; format=flowed", 'quoted-printable')}\r\n\r\n#{quote_if_necessary(@text, @charset)}"
333
+
334
+ # html part
335
+ body << "#{buildbodyboundary("text/html; charset=#{@charset}", 'quoted-printable')}\r\n\r\n#{quote_if_necessary(@html, @charset)}"
336
+
337
+ body << "--#{@bodyboundary}--"
338
+ end
339
+
340
+ return(body.join("\r\n\r\n"))
341
+ end
342
+ end
343
+
344
+ # builds a boundary string for including attachments in the body, expects an attachment hash as built by
345
+ # add_attachment and add_attachment_as
346
+ def buildattachmentboundary(attachment)
347
+ disposition = "Content-Disposition: inline; filename=\"#{attachment['filename']}\""
348
+ boundary = "--#{@attachmentboundary}\r\nContent-Type: #{attachment['mimetype']}; name=\"#{attachment['filename']}\"\r\nContent-Transfer-Encoding: base64\r\n#{disposition}"
349
+ if(attachment['headers'])
350
+ boundary = boundary + "\r\n#{attachment['headers'].join("\r\n")}"
351
+ end
352
+
353
+ return(boundary)
354
+ end
355
+
356
+ # builds a boundary string for inclusion in the body of a message
357
+ def buildbodyboundary(type, encoding)
358
+ return("--#{@bodyboundary}\r\nContent-Type: #{type}\r\nContent-Transfer-Encoding: #{encoding}")
359
+ end
360
+
361
+ # returns a base64 encoded version of the contents of str
362
+ def file_encode(str)
363
+ collection = Array.new()
364
+ enc = [str].pack('m')
365
+ # while(enc.length > 60)
366
+ # collection << enc.slice!(0..59)
367
+ # end
368
+ # collection << enc
369
+ # return(collection.join("\n"))
370
+ return(enc)
371
+ end
372
+
373
+ # Convert the given text into quoted printable format, with an instruction
374
+ # that the text be eventually interpreted in the given charset.
375
+
376
+ def quoted_printable_with_instruction(text, charset)
377
+ text = quoted_printable_encode_header(text)
378
+ "=?#{charset}?Q?#{text}?="
379
+ end
380
+
381
+ # rfc2045 compatible. use rfc2047 for headers (such as the Subject line) instead
382
+ def quoted_printable_encode(text)
383
+ [text].pack('M').gsub(/\n/, "\r\n").chomp.gsub(/=$/, '')
384
+ end
385
+
386
+ # Convert the given character to quoted printable format
387
+ # see http://tools.ietf.org/html/rfc2047
388
+
389
+ require 'enumerator' unless ''.respond_to? :enum_for
390
+
391
+ def quoted_printable_encode_header(text)
392
+ text.enum_for(:each_byte).map do |ord|
393
+ if ord < 128 and ord != 61 # 61 is ascii '='
394
+ ord.chr
395
+ else
396
+ '=%X' % ord
397
+ end
398
+ end.join('').
399
+ chomp.
400
+ gsub(/=$/,'').
401
+ gsub('?', '=3F').
402
+ gsub('_', '=5F').
403
+ gsub(/ /, '_')
404
+ end
405
+
406
+ # A quick-and-dirty regexp for determining whether a string contains any
407
+ # characters that need escaping.
408
+ #--
409
+ # Jun18-08: deprecated, since all multipart blocks are marked quoted-printable, quoting is required
410
+
411
+ # if !defined?(CHARS_NEEDING_QUOTING)
412
+ # CHARS_NEEDING_QUOTING = /[\000-\011\013\014\016-\037\177-\377]/
413
+ # end
414
+
415
+ # Quote the given text if it contains any "illegal" characters
416
+ def quote_if_necessary(text, charset, instruction = false)
417
+ return unless text
418
+ text = text.dup.force_encoding(Encoding::ASCII_8BIT) if text.respond_to?(:force_encoding)
419
+ #(text =~ CHARS_NEEDING_QUOTING) ? (instruction ? quoted_printable_with_instruction(text, charset) : quoted_printable_encode(text)) : text
420
+ instruction ? quoted_printable_with_instruction(text, charset) : quoted_printable_encode(text)
421
+ end
422
+
423
+ # Quote the given address if it needs to be. The address may be a
424
+ # regular email address, or it can be a phrase followed by an address in
425
+ # brackets. The phrase is the only part that will be quoted, and only if
426
+ # it needs to be. This allows extended characters to be used in the
427
+ # "to", "from", "cc", and "bcc" headers.
428
+ def quote_address_if_necessary(address, charset)
429
+ if Array === address
430
+ address.map { |a| quote_address_if_necessary(a, charset) }
431
+ elsif address =~ /^(\S.*)\s+(<.*>)$/
432
+ address = $2
433
+ phrase = quote_if_necessary($1.gsub(/^['"](.*)['"]$/, '\1'), charset, true)
434
+ "\"#{phrase}\" #{address}"
435
+ else
436
+ address
437
+ end
438
+ end
439
+ end
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env ruby
2
+ # coding:utf-8
3
+
4
+ require 'test/unit/ui/console/testrunner'
5
+ require_relative '../lib/kuvert'
6
+
7
+ def get_options()
8
+ options = Hash.new()
9
+
10
+ opts = OptionParser.new() { |opts|
11
+ opts.on_tail("-h", "--help", "Print this message") {
12
+ print(opts)
13
+ exit()
14
+ }
15
+
16
+ opts.on("-s", "--smtpserver SERVER", "SMTP server to use for remote tests") { |server|
17
+ options['smtpserver'] = server
18
+ }
19
+
20
+ opts.on("-f", "--from ADDRESS", "address to send the mail from") { |address|
21
+ options['from'] = address
22
+ }
23
+
24
+ opts.on("-t", "--to ADDRESS", "address to send the mail to") { |address|
25
+ options['to'] = address
26
+ }
27
+
28
+ opts.on("-u", "--username USERNAME", "username for smtp auth (required)") { |username|
29
+ options['username'] = username
30
+ }
31
+
32
+ opts.on("-p", "--password PASSWORD", "password for smtp auth (required)") { |password|
33
+ options['password'] = password
34
+ }
35
+
36
+ }
37
+
38
+ opts.parse(ARGV)
39
+
40
+ return(options)
41
+ end
42
+
43
+
44
+
45
+ class TC_Kuvert < Test::Unit::TestCase
46
+
47
+ def setup()
48
+ @mail = Kuvert.new
49
+ end
50
+
51
+
52
+ def test_set_to
53
+ assert_nothing_raised("exception raised while setting to=") {
54
+ @mail.to = "test@test.com"
55
+ }
56
+
57
+ assert_equal(@mail.to, ["test@test.com"], "to does not equal what it was set to")
58
+
59
+ assert_nothing_raised("exception raised while setting to=") {
60
+ @mail.to = "test@test2.com"
61
+ }
62
+
63
+ # count to headers in the final message to make sure we have only one
64
+ count = 0
65
+ @mail.to_s().each_line() { |line|
66
+ if(line =~ /^To:/i)
67
+ count = count + 1
68
+ end
69
+ }
70
+ assert_equal(1, count, "Count of To: headers expected to be 1, but was #{count}")
71
+ end
72
+
73
+
74
+ def test_set_from
75
+ assert_nothing_raised("exception raised while setting from=") {
76
+ @mail.from = "test@test.com"
77
+ }
78
+
79
+ assert_equal(@mail.from, ["test@test.com"], "from does not equal what it was set to")
80
+
81
+ assert_nothing_raised("exception raised while setting from=") {
82
+ @mail.from = "test@test2.com"
83
+ }
84
+
85
+ # count to headers in the final message to make sure we have only one
86
+ count = 0
87
+ @mail.to_s().each_line() { |line|
88
+ if(line =~ /^From:/i)
89
+ count = count + 1
90
+ end
91
+ }
92
+ assert_equal(1, count, "Count of From: headers expected to be 1, but was #{count}")
93
+ end
94
+
95
+
96
+ def test_set_subject
97
+ assert_nothing_raised("exception raised while setting subject=") {
98
+ @mail.subject = "Test Subject"
99
+ }
100
+
101
+ assert_equal(["=?utf-8?Q?Test_Subject?="], @mail.subject, "subject does not equal what it was set to")
102
+
103
+ assert_nothing_raised("exception raised while setting subject=") {
104
+ @mail.subject = "A Different Subject"
105
+ }
106
+
107
+ # count to headers in the final message to make sure we have only one
108
+ count = 0
109
+ @mail.to_s().each_line() { |line|
110
+ if(line =~ /^Subject:/i)
111
+ count = count + 1
112
+ end
113
+ }
114
+ assert_equal(1, count, "Count of Subject: headers expected to be 1, but was #{count}")
115
+ end
116
+
117
+
118
+ def test_set_header
119
+ assert_nothing_raised("exception raised while setting arbitrary header") {
120
+ @mail.set_header("arbitrary", "some value")
121
+ }
122
+
123
+ assert_equal("some value", @mail.get_header("arbitrary")[0], "arbitrary header does not equal \"some value\"")
124
+
125
+ assert_nothing_raised("exception raised while setting arbitrary header with _") {
126
+ @mail.arbitrary_header = "some _ value"
127
+ }
128
+
129
+ assert_equal(["some _ value"], @mail.get_header("arbitrary-header"), "arbitrary header does not equal \"some _ value\"")
130
+ assert_equal(["some _ value"], @mail.arbitrary_header, "arbitrary header does not equal \"some _ value\"")
131
+
132
+
133
+ assert_nothing_raised("exception raised while setting arbitraryHeader") {
134
+ @mail.arbitraryHeader = "someValue"
135
+ }
136
+
137
+ assert_equal(["someValue"], @mail.get_header("arbitrary-header"), "arbitrary header does not equal \"someValue\"")
138
+ assert_equal(["someValue"], @mail.arbitraryHeader, "arbitrary header does not equal \"someValue\"")
139
+ end
140
+
141
+
142
+ def test_boundary_generator
143
+ 1.upto(50) {
144
+ assert_match(/^----=_NextPart_[a-zA-Z0-9\._]{25}$/, @mail.generate_boundary(), "illegal message boundary generated")
145
+ }
146
+ end
147
+
148
+
149
+ def test_email
150
+ @mail.to="test@test.com"
151
+ @mail.from="test@othertest.com"
152
+ @mail.subject="This is a test"
153
+ @mail.text = "This is a test message with\na few\n\nlines."
154
+
155
+ @mail.attach(File.dirname(__FILE__) + '/testfile.txt')
156
+ @mail.attach(File.dirname(__FILE__) + '/testsheet.xls')
157
+
158
+ if($options['smtpserver'] != nil and $options['to'] != nil and $options['from'] != nil)
159
+ assert_nothing_raised() {
160
+ require('net/smtp')
161
+ Net::SMTP.start($options['smtpserver'], 25, 'mail.from.domain', $options['username'], $options['password'], :cram_md5) { |smtp|
162
+ smtp.send_message(@mail.to_s(), $options['from'], $options['to'])
163
+ }
164
+ }
165
+ end
166
+ end
167
+
168
+
169
+ def test_attach_as
170
+ @mail.to="test@test.com"
171
+ @mail.from="test@othertest.com"
172
+ @mail.subject="This is a test"
173
+ @mail.text = "This is a test message with\na few\n\nlines."
174
+
175
+ @mail.add_attachment_as(File.dirname(__FILE__) + '/testfile.txt', 'newname.txt')
176
+ @mail.add_attachment_as(File.open(File.dirname(__FILE__) + '/testsheet.xls', 'rb'), 'newname.xls', 'application/vnd.ms-excel')
177
+
178
+ if($options['smtpserver'] != nil and $options['to'] != nil and $options['from'] != nil)
179
+ assert_nothing_raised() {
180
+ require('net/smtp')
181
+ Net::SMTP.start($options['smtpserver'], 25, 'mail.from.domain', $options['username'], $options['password'], :cram_md5) { |smtp|
182
+ smtp.send_message(@mail.to_s(), $options['from'], $options['to'])
183
+ }
184
+ }
185
+ end
186
+ end
187
+
188
+ def test_quoted_printable_with_instruction
189
+ @mail.to="test@test.com"
190
+ @mail.from="test@othertest.com"
191
+ @mail.subject="My email subject has a ? in it and also an = and a _ too... Also some non-quoted junk ()!@\#\{\$\%\}"
192
+ @mail.text = "This is a test message with\na few\n\nlines."
193
+ assert_equal(["=?utf-8?Q?My_email_subject_has_a_=3F_in_it_and_also_an_=3D_and_a_=5F_too..._Also_some_non-quoted_junk_()!@\#\{\$\%\}?="], @mail.subject)
194
+ end
195
+
196
+ def test_scandinavian_subject_quoting
197
+ @mail.to="test@test.com"
198
+ @mail.from="test@othertest.com"
199
+ # Three a with dots and three o with dots.
200
+ @mail.subject="\303\244\303\244\303\244\303\266\303\266\303\266"
201
+ @mail.text = "This is a test message with\na few\n\nlines."
202
+ assert_equal(["=?utf-8?Q?=C3=A4=C3=A4=C3=A4=C3=B6=C3=B6=C3=B6?="], @mail.subject)
203
+ end
204
+
205
+ def test_utf8_quoted_printable_with_instruction
206
+ @mail.to="test@test.com"
207
+ @mail.from="test@othertest.com"
208
+ @mail.subject="My email subject has a à which is utf8."
209
+ @mail.text = "This is a test message with\na few\n\nlines."
210
+ assert_equal(["=?utf-8?Q?My_email_subject_has_a_=C3=83_which_is_utf8.?="], @mail.subject)
211
+ end
212
+
213
+ def test_quoted_printable_html
214
+ @mail.to="test@test.com"
215
+ @mail.from="test@othertest.com"
216
+ @mail.subject="some html"
217
+ @mail.html="<a href=\"http://google.com\">click here</a>"
218
+ assert_match('<a href=3D"http://google.com">click here</a>', @mail.to_s)
219
+ end
220
+
221
+ def test_bcc_not_in_headers
222
+ @mail.bcc = 'bcc@test.com'
223
+ assert_no_match(/bcc@test\.com/, @mail.to_s)
224
+ end
225
+
226
+ def test_recipients
227
+ @mail.to="test@test.com"
228
+ @mail.cc="cc@test.com"
229
+ @mail.bcc="bcc@test.com"
230
+ assert_equal(['test@test.com', 'cc@test.com', 'bcc@test.com'], @mail.recipients)
231
+ end
232
+ end
233
+
234
+ $options = get_options()
235
+ Test::Unit::UI::Console::TestRunner.run(TC_Kuvert)
data/test/testfile.txt ADDED
File without changes
File without changes
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kuvert
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - David Powers
8
+ - Cyril David
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-03-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mime-types
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '2.4'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2.4'
28
+ description: Keep MailFactory updated with the times
29
+ email:
30
+ - cyx@cyx.is
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".gems"
36
+ - Makefile
37
+ - README.markdown
38
+ - kuvert.gemspec
39
+ - lib/kuvert.rb
40
+ - test/kuvert_test.rb
41
+ - test/testfile.txt
42
+ - test/testsheet.xls
43
+ homepage: http://github.com/cyx/kuvert
44
+ licenses:
45
+ - MIT
46
+ metadata: {}
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 2.4.5
64
+ signing_key:
65
+ specification_version: 4
66
+ summary: Continuing the MailFactory legacy
67
+ test_files: []