manveru-mailit 2009.06.08

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/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Mailit
2
+
3
+ Mailit is a simple to use library to create and send MIME compliant e-mail with
4
+ attachments and various encodings.
5
+
6
+ This is a fork of MailFactory and provides a mostly identical API but has been
7
+ cleaned up, simplified, and made compliant to common Ruby idioms. I would like
8
+ to thank David Powers for the original MailFactory, it served me well for many
9
+ years.
10
+
11
+ Copyright (c) 2005-2008 David Powers.
12
+ Copyright (c) 2009 Michael Fellinger.
13
+
14
+ This program is free software. You can re-distribute and/or modify this program
15
+ under the same terms as Ruby itself.
16
+
17
+
18
+ ## Dependencies
19
+
20
+ Any Ruby since 1.8.4 should work.
21
+ Mailit can use the Rack or Mime::Types libraries to determine the mime-type of
22
+ attachments automatically, but they are optional.
23
+
24
+
25
+ ## Usage of Mailit::Mail
26
+
27
+ require 'net/smtp'
28
+ require 'mailit'
29
+
30
+ mail = Mailit::Mail.new
31
+ mail.to = 'test@test.com'
32
+ mail.from = 'sender@sender.com'
33
+ mail.subject 'Here are some files for you!'
34
+ mail.text = 'This is what people with plain text mail readers will see'
35
+ mail.html = "A little something <b>special</b> for people with HTML readers'
36
+ mail.attach('/etc/fstab')
37
+ mail.attach('/home/manveru/.vimrc')
38
+
39
+ puts mail
40
+
41
+
42
+ ## Usage of Mailit::Mailer
43
+
44
+ Using the mail variable from above example
45
+
46
+ mailer = Mailit::Mailer.new
47
+
48
+ mailer.send(mail, :server => 'smtp.example.com', :port => 25,
49
+ :domain => 'example.com', :password => 'foo')
50
+
51
+
52
+ ## Todo:
53
+
54
+ MailFactory has a method_missing that handles getting and setting of arbitrary
55
+ headers.
56
+ I went for the less magical #[] and #[]= methods, maybe someone can add the
57
+ MailFactory behaviour.
58
+
59
+ ## Thanks to
60
+
61
+ * Michael Thompson (AKA:nylon)
62
+
63
+ Making mailer work on windows
@@ -0,0 +1,367 @@
1
+ require 'time'
2
+ require 'pathname'
3
+ require 'enumerator' unless 'String'.respond_to?(:enum_for)
4
+
5
+ module Mailit
6
+
7
+ # = Overview:
8
+ #
9
+ # A simple to use class to generate RFC compliant MIME email.
10
+ #
11
+ # MailIt is a fork of MailFactory and provides a mostly identical API but has
12
+ # been cleaned up, simplified, and made compliant to common Ruby idioms.
13
+ #
14
+ # Copyright (c) 2005-2008 David Powers.
15
+ # Copyright (c) 2009 Michael Fellinger.
16
+ #
17
+ # This program is free software. You can re-distribute and/or
18
+ # modify this program under the same terms as Ruby itself.
19
+ #
20
+ # = Usage:
21
+ #
22
+ # require 'net/smtp'
23
+ # require 'mailit'
24
+ #
25
+ # mail = Mailit::Mail.new
26
+ # mail.to = 'test@test.com'
27
+ # mail.from = 'sender@sender.com'
28
+ # mail.subject 'Here are some files for you!'
29
+ # mail.text = 'This is what people with plain text mail readers will see'
30
+ # mail.html = "A little something <b>special</b> for people with HTML readers'
31
+ # mail.attach('/etc/fstab')
32
+ # mail.attach('/home/manveru/.vimrc')
33
+ #
34
+ # server = 'smtp1.testmailer.com'
35
+ # port = 25
36
+ # domain = 'mail.from.domain'
37
+ # password = 'foo'
38
+ #
39
+ # Net::SMTP.start(server, port, domain, mail.from, password, :cram_md5) do |smtp|
40
+ # smtp.send_message(mail.to_s, mail.from, mail.to)
41
+ # end
42
+ #
43
+ # = Todo:
44
+ #
45
+ # * MailFactory has a method_missing that handles getting and setting of
46
+ # arbitrary headers.
47
+ # I went for the less magical #[] and #[]= methods.
48
+ # Maybe someone can add the MailFactory behaviour.
49
+ class Mail
50
+ VERSION = '2009.03.02'
51
+
52
+ BOUNDARY_CHARS = [*'a'..'z'] + [*'A'..'Z'] + [*'0'..'9'] + ['.', '_']
53
+ BOUNDARY_PREFIX = "----=_NextPart_"
54
+
55
+ # body_boundary, encoding
56
+ BODY_BOUNDARY = "--%s\r\nContent-Type: %s\r\nContent-Transfer-Encoding: %s"
57
+
58
+ # attachment_boundary, mimetype, filename, filename
59
+ ATTACHMENT_BOUNDARY = "--%s\r\nContent-Type: %s; name=%p\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: inline; filename=%p"
60
+
61
+ HTML_BODY = <<BODY.strip
62
+ <html>
63
+ <head>
64
+ <meta http-equiv="Content-Type" content="text/html; charset=%s">
65
+ </head>
66
+ <body bgcolor="#ffffff" text="#000000">
67
+ %s
68
+ </body>
69
+ </html>
70
+ BODY
71
+
72
+ OPTIONS = {
73
+ :date => true,
74
+ :message_id => lambda{|mail|
75
+ time = Time.now
76
+ domain = mail['from'].first.to_s.split('@').last || 'localhost'
77
+ message_id = "<%f.%d.%d@%s>" % [time, $$, time.object_id, domain]
78
+ }
79
+ }
80
+
81
+
82
+ attr_accessor :charset, :text, :html, :attachment_boundary, :body_boundary
83
+ attr_reader :headers, :attachments
84
+
85
+ # Create an instance of {Mailit::Mailer}.
86
+ #
87
+ # @option options [String] :to
88
+ # @option options [String] :from
89
+ # @option options [String] :subject
90
+ # @option options [String] :text
91
+ # @option options [String] :html
92
+ # @author manveru
93
+ def initialize(options = {})
94
+ @headers = []
95
+ @attachments = []
96
+ @attachment_boundary = self.class.generate_boundary
97
+ @body_boundary = self.class.generate_boundary
98
+ @charset = 'utf-8'
99
+ @html = @text = nil
100
+
101
+ options.each{|key, value| __send__("#{key}=", value) }
102
+ end
103
+
104
+ def construct(options = {})
105
+ options = OPTIONS.merge(options)
106
+ time = Time.now
107
+
108
+ if message_id = options[:message_id]
109
+ self['Message-ID'] = message_id.call(self) unless self['Message-Id'].any?
110
+ end
111
+
112
+ if options[:date]
113
+ self['Date'] = time.rfc2822 unless self['Date'].any?
114
+ end
115
+
116
+ if multipart?
117
+ self['MIME-Version'] = '1.0' unless self['MIME-Version'].any?
118
+
119
+ unless self['Content-Type'].any?
120
+ if @attachments.any?
121
+ content_type = ('multipart/alternative; boundary=%p' % body_boundary)
122
+ else
123
+ content_type = ('multipart/mixed; boundary=%p' % attachment_boundary)
124
+ end
125
+
126
+ self['Content-Type'] = content_type
127
+ end
128
+ end
129
+
130
+ "#{header_string}#{body_string}"
131
+ end
132
+ alias to_s construct
133
+
134
+ ## Attachments
135
+
136
+ def add_attachment(filename, mimetype = nil, headers = nil)
137
+ container = {
138
+ :filename => Pathname.new(filename).basename,
139
+ :mimetype => (mimetype || mime_type_for(filename)),
140
+ }
141
+
142
+ add_attachment_common(container, file, headers)
143
+ end
144
+ alias attach add_attachment
145
+
146
+ def add_attachment_as(file, filename, mimetype = nil, headers = nil)
147
+ container = {
148
+ :filename => filename,
149
+ :mimetype => (mimetype || mime_type_for(file))
150
+ }
151
+
152
+ add_attachment_common(container, file, headers)
153
+ end
154
+ alias attach_as add_attachment_as
155
+
156
+ ## Shortcuts
157
+
158
+ def multipart?
159
+ html || attachments.size > 0
160
+ end
161
+
162
+ def html=(html)
163
+ @html = HTML_BODY % [charset, html]
164
+ end
165
+
166
+ def raw_html=(html)
167
+ @html = html
168
+ end
169
+
170
+ def message_id=(id)
171
+ self['Message-ID'] = id
172
+ end
173
+
174
+ def send(options = {})
175
+ Mailer.send(self, options)
176
+ end
177
+
178
+ def defer_send(options = {})
179
+ Mailer.defer_send(self, options)
180
+ end
181
+
182
+ ## Header handling
183
+
184
+ def add_header(header, value)
185
+ case header.to_s.downcase
186
+ when /^subject$/i
187
+ value = quoted_printable_with_instruction(value)
188
+ when /^(from|to|bcc|reply-to)$/i
189
+ value = quote_address_if_necessary(value, charset)
190
+ end
191
+
192
+ @headers << [header, value]
193
+ end
194
+
195
+ def set_header(header, value)
196
+ remove_header(header)
197
+ add_header(header, value)
198
+ end
199
+ alias []= set_header
200
+
201
+ def remove_header(header)
202
+ regex = /^#{Regexp.escape(header)}/i
203
+
204
+ @headers.reject!{|key, value| key =~ regex }
205
+ end
206
+
207
+ def get_header(header)
208
+ regex = /^#{Regexp.escape(header)}/i
209
+
210
+ @headers.map{|key, value| value if regex =~ key }.compact
211
+ end
212
+ alias [] get_header
213
+
214
+ def header_string
215
+ headers.join("\r\n") << "\r\n\r\n"
216
+ end
217
+
218
+ MIME_INDICATOR = "This is a multi-part message in MIME format.\r\n\r\n--%s\r\nContent-Type: multipart/alternative; boundary=%p"
219
+
220
+ def body_string
221
+ return text unless multipart?
222
+
223
+ body = [ MIME_INDICATOR % [attachment_boundary, body_boundary] ]
224
+ body << build_body_boundary("text/plain; charset=#{charset} format=flowed")
225
+ body << "\r\n\r\n" << quote_if_necessary(text, charset)
226
+
227
+ if html
228
+ body << build_body_boundary("text/html; charset=#{charset}")
229
+ body << "\r\n\r\n" << quote_if_necessary(html, charset)
230
+ end
231
+
232
+ body << "--#{body_boundary}--"
233
+
234
+ attachments.each do |attachment|
235
+ body << build_attachment_boundary(attachment)
236
+ body << "\r\n\r\n" << attachment[:attachment]
237
+ body << "\r\n--#{attachment_boundary}--"
238
+ end
239
+
240
+ body.join("\r\n\r\n")
241
+ end
242
+
243
+ private
244
+
245
+ def add_attachment_common(container, file, headers)
246
+ container[:attachment] = file_read(file)
247
+ container[:headers] = headers_prepare(headers)
248
+ self.attachments << container
249
+ end
250
+
251
+ def headers_prepare(headers)
252
+ case headers
253
+ when Array
254
+ container[:headers] = headers
255
+ else
256
+ container[:headers] = headers.split(/\r?\n/)
257
+ end
258
+ end
259
+
260
+ def quoted_printable_with_instruction(text)
261
+ text = encode_quoted_printable_rfc2047(text)
262
+ "=?#{charset}?Q?#{text}?="
263
+ end
264
+
265
+ def quote_if_necessary(text, charset, instruction = false)
266
+ return unless text
267
+
268
+ if text.respond_to?(:force_encoding)
269
+ text = text.dup.force_encoding(Encoding::ASCII_8BIT)
270
+ end
271
+
272
+ if instruction
273
+ quoted_printable_with_instruction(text)
274
+ else
275
+ encode_quoted_printable_rfc2045(text)
276
+ end
277
+ end
278
+
279
+ def quote_address_if_necessary(address, charset)
280
+ case address
281
+ when Array
282
+ address.map{|addr| quote_address_if_necessary(addr, charset) }
283
+ when /^(\S.*)\s+(<.*>)$/
284
+ phrase = $1.gsub(/^['"](.*)['"]$/, '\1')
285
+ address = $2
286
+
287
+ phrase = quote_if_necessary(phrase, charset, true)
288
+
289
+ "%p %s" % [phrase, address]
290
+ else
291
+ address
292
+ end
293
+ end
294
+
295
+ def encode_file(string)
296
+ [string].pack('m')
297
+ end
298
+
299
+ def file_read(file)
300
+ case file
301
+ when String, Pathname
302
+ File.open(file.to_s, 'rb') do |io|
303
+ encode_file(io.read)
304
+ end
305
+ else
306
+ encode_file(file.read)
307
+ end
308
+ end
309
+
310
+ def encode_quoted_printable_rfc2045(string)
311
+ [string].pack('M').gsub(/\n/, "\r\n").chomp.gsub(/=$/, '')
312
+ end
313
+
314
+ def encode_quoted_printable_rfc2047(string)
315
+ string.enum_for(:each_byte).map{|ord|
316
+ if ord < 128 and ord != 61 # 61 is ascii '='
317
+ ord.chr
318
+ else
319
+ '=%X' % ord
320
+ end
321
+ }.join('').chomp.
322
+ gsub(/=$/,'').gsub('?', '=3F').gsub('_', '=5F').gsub(/ /, '_')
323
+ end
324
+
325
+ def build_body_boundary(type, encoding = 'quoted-printable')
326
+ BODY_BOUNDARY % [ body_boundary, type, encoding ]
327
+ end
328
+
329
+ def build_attachment_boundary(attachment)
330
+ mime, file, headers = attachment.values_at(:mimetype, :filename, :headers)
331
+
332
+ boundary = ATTACHMENT_BOUNDARY % [attachment_boundary, mime, file, file]
333
+ boundary << "\r\n%s" % headers.join("\r\n") if headers
334
+
335
+ boundary
336
+ end
337
+
338
+ # Try to get the
339
+ def mime_type_for(filename, override = nil)
340
+ override || Mime.type_for(filename)
341
+ end
342
+
343
+ ## Header shortcuts
344
+
345
+ def self.header_accessors(hash)
346
+ hash.each{|k,v| header_accessor(k, v) }
347
+ end
348
+
349
+ def self.header_accessor(method, header)
350
+ public
351
+ eval("def %s; self[%p].first; end" % [method, header.to_s])
352
+ eval("def %s=(o); self[%p] = o; end" % [method, header.to_s])
353
+ end
354
+
355
+ header_accessors(:reply_to => 'Reply-To', :to => :to, :from => :from,
356
+ :subject => :subject, :bcc => :bcc)
357
+
358
+ def self.generate_boundary(size = 25, chars = BOUNDARY_CHARS)
359
+ char_count = chars.size
360
+ postfix = Array.new(size){
361
+ chars[rand(char_count)]
362
+ }.join
363
+
364
+ return "#{BOUNDARY_PREFIX}#{postfix}"
365
+ end
366
+ end
367
+ end
@@ -0,0 +1,129 @@
1
+ module Mailit
2
+ # The Mailer is an abstraction layer for different SMTP clients, it provides
3
+ # #send and #defer_send methods
4
+ #
5
+ # At the time of writing, Net::SMTP and EventMachine::SmtpClient are
6
+ # supported, it should be trivial to add support for any other client.
7
+ #
8
+ # The difference between #send and #defer_send depends on the backend, but
9
+ # usually #send will block until the mail was sent while #defer_send does it
10
+ # in the background and allows you to continue execution immediately.
11
+ #
12
+ # @example Usage
13
+ #
14
+ # mail = Mailit::Mail.new
15
+ # mail.to = 'test@test.com'
16
+ # mail.from = 'sender@sender.com'
17
+ # mail.subject 'Here are some files for you!'
18
+ # mail.text = 'This is what you see with a plaintext mail reader'
19
+ # mail.attach('/home/manveru/.vimrc')
20
+ #
21
+ # # Send and wait until sending finished
22
+ # Mailit::Mailer.send(mail)
23
+ #
24
+ # # Send in background thread and continue doing other things
25
+ # Mailit::Mailer.defer_send(mail)
26
+ #
27
+ # The default Mailer backend is Mailit::Mailer::NetSmtp, you can change the
28
+ # default by including another module into Mailit::mailer
29
+ #
30
+ # @example Using Mailt::Mailer::EventMachine by inclusion
31
+ #
32
+ # class Mailit::Mailer
33
+ # include Mailit::Mailer::EventMachine
34
+ # end
35
+ #
36
+ # Another way is to extend an instance of Mailer with the backend you want to
37
+ # use, which will not affect other instances.
38
+ #
39
+ # @example Using Mailit::mailer::EventMachine by extension
40
+ #
41
+ # mailer = Mailit::Mailer.new
42
+ # mailer.extend(Mailit::Mailer::EventMachine)
43
+ class Mailer
44
+ OPTIONS = {
45
+ :server => 'smtp.localhost',
46
+ :port => 25,
47
+ :domain => 'localhost',
48
+ :username => 'foo',
49
+ :password => 'foo',
50
+ :noop => false,
51
+ :auth_type => :login, # :plain, :login, :cram_md5
52
+ :starttls => false, # only useful for EventMachine::SmtpClient
53
+ }
54
+
55
+ def self.send(mail, options = {})
56
+ new.send(mail, options)
57
+ end
58
+
59
+ def self.defer_send(mail, options = {})
60
+ new.defer_send(mail, options)
61
+ end
62
+
63
+ undef :send
64
+
65
+ attr_reader :options
66
+
67
+ def initialize(options = {})
68
+ @options = OPTIONS.merge(options)
69
+ extend NetSmtp unless respond_to?(:send)
70
+ end
71
+
72
+ private
73
+
74
+ def settings(override, *keys)
75
+ options.merge(override).values_at(*keys)
76
+ end
77
+
78
+ module NetSmtp
79
+ def send(mail, override = {})
80
+ require 'net/smtp'
81
+
82
+ server, port, domain, username, password, auth_type =
83
+ settings(override, :server, :port, :domain, :username, :password, :auth_type)
84
+
85
+ ::Net::SMTP.start(server, port, domain, username, password, auth_type) do |smtp|
86
+ return if noop
87
+ smtp.send_message(mail.to_s, mail.from, mail.to)
88
+ end
89
+ end
90
+
91
+ def defer_send(mail, override = {})
92
+ Thread.new{ send(mail, override) }
93
+ end
94
+ end
95
+
96
+ # Allows you to comfortably use the EventMachine::SmtpClient.
97
+ # In order to use it, you have to first include this module into
98
+ # Mailit::Mailer or extend the Mailit::Mailer instance with it.
99
+ module EventMachine
100
+
101
+ # This assumes that EventMachine was required and we are inside the
102
+ # EventMachine::run block.
103
+ #
104
+ # Since EM implements some parts of the mail building we'll have to
105
+ # deconstruct our mail a bit.
106
+ # On the upside, it seems like it supports STARTTLS (without certificate
107
+ # options though)
108
+ def send(mail, options = {})
109
+ server, port, domain, username, password, auth_type =
110
+ settings(override, :server, :port, :domain, :username, :password, :auth_type)
111
+
112
+ mail.construct # prepare headers and body
113
+
114
+ em_options = { :port => port, :host => host, :domain => domain,
115
+ :from => mail.from, :to => mail.to, :header => mail.header_string,
116
+ :body => mail.body_string }
117
+
118
+ if auth_type
119
+ em_options[:auth] = {
120
+ :type => auth_type, :username => username, :password => password }
121
+ end
122
+
123
+ ::EventMachine::SmtpClient.send(em_options)
124
+ end
125
+
126
+ alias defer_send send
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,49 @@
1
+ module Mailit
2
+ module Mime
3
+ module_function
4
+
5
+ def mime_for(filename)
6
+ detect_handler unless defined?(@mime_handler)
7
+ send(@mime_handler, filename)
8
+ end
9
+
10
+ def detect_handler
11
+ try_require('rubygems')
12
+
13
+ if try_require('mime/types')
14
+ @mime_handler = :from_mime_types
15
+ elsif try_require('rack') and try_require('rack/mime')
16
+ @mime_handler = :from_rack
17
+ else
18
+ require 'webrick/httputils'
19
+ @webrick_types = WEBrick::HTTPUtils::DefaultMimeTypes.dup
20
+ try_extend_webrick('/etc/mime.types')
21
+ @mime_handler = :from_webrick
22
+ end
23
+ end
24
+
25
+ def from_mime_types(filename)
26
+ MIME::Types.type_for(filename) || 'application/octet-stream'
27
+ end
28
+
29
+ def from_rack(filename)
30
+ Rack::Mime.mime_type(File.extname(filename))
31
+ end
32
+
33
+ def from_webrick(filename)
34
+ WEBrick::HTTPUtils.mime_type(filename, @webrick_types)
35
+ end
36
+
37
+ def try_extend_webrick(file)
38
+ hash = WEBrick::HTTPUtils.load_mime_types(file)
39
+ @webrick_types.merge!(hash)
40
+ rescue
41
+ end
42
+
43
+ def try_require(lib)
44
+ require lib
45
+ true
46
+ rescue LoadError
47
+ end
48
+ end
49
+ end
data/lib/mailit.rb ADDED
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ module Mailit
4
+ VERSION = '2009.03.10'
5
+ end
6
+
7
+ require 'mailit/mime'
8
+ require 'mailit/mail'
9
+ require 'mailit/mailer'
data/mailit.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "mailit"
3
+ s.version = "2009.06.08"
4
+
5
+ s.summary = "RFC compliant MIME email generation and SMTP mailing."
6
+ s.description = "Simple to use class to generate RFC compliant MIME email."
7
+ s.platform = "ruby"
8
+ s.has_rdoc = true
9
+ s.author = "Michael 'manveru' Fellinger"
10
+ s.email = "m.fellinger@gmail.com"
11
+ s.homepage = "http://github.com/manveru/mailit"
12
+ s.require_path = "lib"
13
+
14
+ s.files = [
15
+ "README.md",
16
+ "lib/mailit.rb",
17
+ "lib/mailit/mail.rb",
18
+ "lib/mailit/mailer.rb",
19
+ "lib/mailit/mime.rb",
20
+ "mailit.gemspec",
21
+ "spec/helper.rb",
22
+ "spec/mailit/mail.rb",
23
+ "spec/mailit/mailer.rb",
24
+ ]
25
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,4 @@
1
+ require File.expand_path("#{__FILE__}/../../lib/mailit")
2
+ require 'bacon'
3
+
4
+ Bacon.summary_on_exit
@@ -0,0 +1,108 @@
1
+ # Encoding: UTF-8
2
+ require 'spec/helper'
3
+
4
+ # The specs are translated from the Test::Unit tests of MailFactory.
5
+ #
6
+ # TODO:
7
+ # * test_attach_as
8
+ # * test_email
9
+
10
+ describe Mailit::Mail do
11
+ should 'set and get headers' do
12
+ mail = Mailit::Mail.new
13
+
14
+ mail.set_header('arbitrary', 'some value')
15
+ mail.get_header('arbitrary').should == ['some value']
16
+
17
+ mail.set_header('arbitrary-header', 'some _ value')
18
+ mail.get_header('arbitrary-header').should == ['some _ value']
19
+ end
20
+
21
+ should 'generate valid boundaries' do
22
+ 50.times do
23
+ boundary = Mailit::Mail.generate_boundary
24
+ boundary.should =~ /^----=_NextPart_[a-zA-Z0-9_.]{25}$/
25
+ end
26
+ end
27
+
28
+ should 'make mail with recipient' do
29
+ mail = Mailit::Mail.new
30
+
31
+ mail.to = 'test@test.com'
32
+ mail.to.should == 'test@test.com'
33
+
34
+ mail.to = 'test@test2.com'
35
+ mail.to.should == 'test@test2.com'
36
+
37
+ mail.headers.size.should == 1 # make sure the previous was deleted
38
+ end
39
+
40
+ should 'make mail with sender' do
41
+ mail = Mailit::Mail.new
42
+
43
+ mail.from = 'test@test.com'
44
+ mail.from.should == 'test@test.com'
45
+
46
+ mail.from = 'test@test2.com'
47
+ mail.from.should == 'test@test2.com'
48
+
49
+ mail.headers.size.should == 1 # make sure the previous was deleted
50
+ end
51
+
52
+ should 'set correct subject' do
53
+ mail = Mailit::Mail.new
54
+
55
+ mail.subject = 'Test Subject'
56
+ mail.subject.should == '=?utf-8?Q?Test_Subject?='
57
+
58
+ mail.subject = 'A Different Subject'
59
+ mail.subject.should == '=?utf-8?Q?A_Different_Subject?='
60
+
61
+ mail.headers.size.should == 1 # make sure the previous was deleted
62
+ end
63
+
64
+ should 'use quoted printable with instruction' do
65
+ mail = Mailit::Mail.new
66
+
67
+ mail.to = 'test@test.com'
68
+ mail.from = 'test@othertest.com'
69
+ mail.subject = "My email subject has a ? in it and also an = and a _ too... Also some non-quoted junk ()!@\#\{\$\%\}"
70
+ mail.text = "This is a test message with\na few\n\nlines."
71
+
72
+ mail.subject.should == "=?utf-8?Q?My_email_subject_has_a_=3F_in_it_and_also_an_=3D_and_a_=5F_too..._Also_some_non-quoted_junk_()!@\#\{\$\%\}?="
73
+ end
74
+
75
+ should 'use subject quoting for scandinavian string' do
76
+ mail = Mailit::Mail.new
77
+
78
+ mail.to = "test@test.com"
79
+ mail.from = "test@othertest.com"
80
+ # Three a with dots and three o with dots.
81
+ mail.subject = "\303\244\303\244\303\244\303\266\303\266\303\266"
82
+ mail.text = "This is a test message with\na few\n\nlines."
83
+
84
+ mail.subject.should == "=?utf-8?Q?=C3=A4=C3=A4=C3=A4=C3=B6=C3=B6=C3=B6?="
85
+ end
86
+
87
+ should 'use subject quoting for utf-8 string' do
88
+ mail = Mailit::Mail.new
89
+
90
+ mail.to = "test@test.com"
91
+ mail.from = "test@othertest.com"
92
+ mail.subject = "My email subject has a à which is utf8."
93
+ mail.text = "This is a test message with\na few\n\nlines."
94
+
95
+ mail.subject.should == "=?utf-8?Q?My_email_subject_has_a_=C3=83_which_is_utf8.?="
96
+ end
97
+
98
+ should 'encode html as quoted printable' do
99
+ mail = Mailit::Mail.new
100
+
101
+ mail.to = "test@test.com"
102
+ mail.from = "test@othertest.com"
103
+ mail.subject = "some html"
104
+ mail.html = "<a href=\"http://google.com\">click here</a>"
105
+
106
+ mail.to_s.should.include('<a href=3D"http://google.com">click here</a>')
107
+ end
108
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec/helper'
2
+
3
+ class MockSMTP
4
+ INSTANCES = []
5
+
6
+ def self.start(*args, &block)
7
+ INSTANCES << new(*args, &block)
8
+ end
9
+
10
+ attr_reader :start_args, :result, :send_message_args
11
+
12
+ def initialize(*args, &block)
13
+ @start_args = args
14
+ yield(self)
15
+ end
16
+
17
+ def send_message(*args)
18
+ @send_message_args = args
19
+ end
20
+ end
21
+
22
+ Mailit::Mail::OPTIONS[:message_id] = lambda{|mail| '1234' }
23
+
24
+ describe Mailit::Mailer do
25
+ it 'sends a mail' do
26
+ mail = Mailit::Mail.new(
27
+ :to => 'test@example.com',
28
+ :from => 'sender@example.com',
29
+ :subject => 'Here are some files for you!',
30
+ :text => 'Some text about that')
31
+
32
+ mailer = Mailit::Mailer.new
33
+
34
+ mailer.send(mail, :server => 'smtp.example.com', :port => 25,
35
+ :domain => 'example.com', :password => 'foo',
36
+ :mailer => MockSMTP)
37
+
38
+ mock = MockSMTP::INSTANCES.last
39
+ mock.start_args.should == [
40
+ 'smtp.example.com', 25,
41
+ 'example.com',
42
+ 'sender@example.com',
43
+ 'foo',
44
+ :cram_md5
45
+ ]
46
+ mock.send_message_args.should == [mail.to_s, mail.from, mail.to]
47
+ end
48
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: manveru-mailit
3
+ version: !ruby/object:Gem::Version
4
+ version: 2009.06.08
5
+ platform: ruby
6
+ authors:
7
+ - Michael 'manveru' Fellinger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Simple to use class to generate RFC compliant MIME email.
17
+ email: m.fellinger@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README.md
26
+ - lib/mailit.rb
27
+ - lib/mailit/mail.rb
28
+ - lib/mailit/mailer.rb
29
+ - lib/mailit/mime.rb
30
+ - mailit.gemspec
31
+ - spec/helper.rb
32
+ - spec/mailit/mail.rb
33
+ - spec/mailit/mailer.rb
34
+ has_rdoc: true
35
+ homepage: http://github.com/manveru/mailit
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.2.0
57
+ signing_key:
58
+ specification_version: 2
59
+ summary: RFC compliant MIME email generation and SMTP mailing.
60
+ test_files: []
61
+