mailit 2009.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/AUTHORS +6 -0
- data/CHANGELOG +76 -0
- data/MANIFEST +28 -0
- data/README.md +63 -0
- data/Rakefile +84 -0
- data/lib/mailit.rb +8 -0
- data/lib/mailit/mail.rb +367 -0
- data/lib/mailit/mailer.rb +131 -0
- data/lib/mailit/mime.rb +49 -0
- data/lib/mailit/version.rb +3 -0
- data/lib/version.rb +3 -0
- data/mailit.gemspec +27 -0
- data/spec/helper.rb +4 -0
- data/spec/mailit/mail.rb +108 -0
- data/spec/mailit/mailer.rb +48 -0
- data/tasks/authors.rake +33 -0
- data/tasks/bacon.rake +70 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/copyright.rake +38 -0
- data/tasks/gem.rake +23 -0
- data/tasks/gem_installer.rake +76 -0
- data/tasks/install_dependencies.rake +6 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +23 -0
- data/tasks/release.rake +52 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/setup.rake +15 -0
- data/tasks/yard.rake +4 -0
- metadata +82 -0
data/AUTHORS
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
[78c844d | 2009-08-25 21:40:40 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
2
|
+
|
3
|
+
* Another fix
|
4
|
+
|
5
|
+
[fb25c19 | 2009-08-25 21:40:01 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
6
|
+
|
7
|
+
* Version 2009.08
|
8
|
+
|
9
|
+
[2e6d77a | 2009-08-25 21:38:53 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
10
|
+
|
11
|
+
* Fix Rakefile
|
12
|
+
|
13
|
+
[585554d | 2009-08-25 05:11:42 UTC] Kevin Berry <kevin@opensourcealchemist.com>
|
14
|
+
|
15
|
+
* Take in Pistos's patch, make my own patch to get running for current project, and add seedling structure.
|
16
|
+
|
17
|
+
[db73002 | 2009-08-06 06:50:35 UTC] Jake Douglas <jakecdouglas@gmail.com>
|
18
|
+
|
19
|
+
* NetSMTP and EventMachine version both actually send mail now. Previous configuration didn't override the #send method correctly so the EM methods weren't loaded. The EM module may only be included now, not used with extend.
|
20
|
+
|
21
|
+
Signed-off-by: Michael Fellinger <m.fellinger@gmail.com>
|
22
|
+
|
23
|
+
[9a36e2f | 2009-08-06 05:39:26 UTC] Jake Douglas <jakecdouglas@gmail.com>
|
24
|
+
|
25
|
+
* get the value of :noop from the options hash in NetSmtp#send
|
26
|
+
|
27
|
+
Signed-off-by: Michael Fellinger <m.fellinger@gmail.com>
|
28
|
+
|
29
|
+
[c6da60b | 2009-06-08 13:52:33 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
30
|
+
|
31
|
+
* Release new version
|
32
|
+
|
33
|
+
[185cf45 | 2009-06-08 13:51:07 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
34
|
+
|
35
|
+
* Fix long outstanding issues
|
36
|
+
|
37
|
+
[e429f3b | 2009-04-12 13:38:16 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
38
|
+
|
39
|
+
* Major refactor of Mailer, add support for EventMachine::SmtpClient and remove render_send
|
40
|
+
|
41
|
+
[341d76a | 2009-04-12 13:23:33 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
42
|
+
|
43
|
+
* Make Mail#header_string and Mail#body_string public
|
44
|
+
|
45
|
+
[5716124 | 2009-03-15 14:26:27 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
46
|
+
|
47
|
+
* Add auth_type and username options for Mailer#send, should work on windows now
|
48
|
+
|
49
|
+
[ff38041 | 2009-03-10 21:02:58 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
50
|
+
|
51
|
+
* Add gemspec
|
52
|
+
|
53
|
+
[07b92d0 | 2009-03-10 20:49:36 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
54
|
+
|
55
|
+
* Add Mailit::Mime - detects and uses available mime providers
|
56
|
+
|
57
|
+
[584398c | 2009-03-10 20:48:49 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
58
|
+
|
59
|
+
* Little improvment to style
|
60
|
+
|
61
|
+
[194c990 | 2009-03-10 20:19:08 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
62
|
+
|
63
|
+
* Add warning if no mime-type detection is possible
|
64
|
+
|
65
|
+
[184b20d | 2009-03-10 20:18:54 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
66
|
+
|
67
|
+
* Add Version
|
68
|
+
|
69
|
+
[74e9ca3 | 2009-03-10 20:18:35 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
70
|
+
|
71
|
+
* Add readme
|
72
|
+
|
73
|
+
[0a4bcad | 2009-03-10 20:02:28 UTC] Michael Fellinger <m.fellinger@gmail.com>
|
74
|
+
|
75
|
+
* Initial commit
|
76
|
+
|
data/MANIFEST
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
AUTHORS
|
2
|
+
CHANGELOG
|
3
|
+
MANIFEST
|
4
|
+
README.md
|
5
|
+
Rakefile
|
6
|
+
lib/mailit.rb
|
7
|
+
lib/mailit/mail.rb
|
8
|
+
lib/mailit/mailer.rb
|
9
|
+
lib/mailit/mime.rb
|
10
|
+
lib/mailit/version.rb
|
11
|
+
lib/version.rb
|
12
|
+
mailit.gemspec
|
13
|
+
spec/helper.rb
|
14
|
+
spec/mailit/mail.rb
|
15
|
+
spec/mailit/mailer.rb
|
16
|
+
tasks/authors.rake
|
17
|
+
tasks/bacon.rake
|
18
|
+
tasks/changelog.rake
|
19
|
+
tasks/copyright.rake
|
20
|
+
tasks/gem.rake
|
21
|
+
tasks/gem_installer.rake
|
22
|
+
tasks/install_dependencies.rake
|
23
|
+
tasks/manifest.rake
|
24
|
+
tasks/rcov.rake
|
25
|
+
tasks/release.rake
|
26
|
+
tasks/reversion.rake
|
27
|
+
tasks/setup.rake
|
28
|
+
tasks/yard.rake
|
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
|
data/Rakefile
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
begin; require 'rubygems'; rescue LoadError; end
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/clean'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
require 'time'
|
7
|
+
require 'date'
|
8
|
+
require './lib/mailit'
|
9
|
+
|
10
|
+
PROJECT_SPECS = FileList[
|
11
|
+
'spec/*/**/*.rb'
|
12
|
+
]
|
13
|
+
|
14
|
+
PROJECT_MODULE = 'Mailit'
|
15
|
+
PROJECT_README = 'README'
|
16
|
+
#PROJECT_RUBYFORGE_GROUP_ID = 3034
|
17
|
+
PROJECT_COPYRIGHT_SUMMARY = [
|
18
|
+
"# Copyright (c) 2008-#{Time.now.year} The Rubyists, LLC (effortless systems) <rubyists@rubyists.com>",
|
19
|
+
"# Distributed under the terms of the MIT license.",
|
20
|
+
"# See the LICENSE file which accompanies this software for the full text",
|
21
|
+
"#"
|
22
|
+
]
|
23
|
+
PROJECT_COPYRIGHT = PROJECT_COPYRIGHT_SUMMARY + [
|
24
|
+
"# Permission is hereby granted, free of charge, to any person obtaining a copy",
|
25
|
+
'# of this software and associated documentation files (the "Software"), to deal',
|
26
|
+
"# in the Software without restriction, including without limitation the rights",
|
27
|
+
"# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell",
|
28
|
+
"# copies of the Software, and to permit persons to whom the Software is",
|
29
|
+
"# furnished to do so, subject to the following conditions:",
|
30
|
+
"#",
|
31
|
+
"# The above copyright notice and this permission notice shall be included in",
|
32
|
+
"# all copies or substantial portions of the Software.",
|
33
|
+
"#",
|
34
|
+
'# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR',
|
35
|
+
"# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
|
36
|
+
"# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE",
|
37
|
+
"# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
|
38
|
+
"# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,",
|
39
|
+
"# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN",
|
40
|
+
"# THE SOFTWARE."
|
41
|
+
]
|
42
|
+
|
43
|
+
PROJECT_VERSION =
|
44
|
+
if version = ENV['PROJECT_VERSION'] || ENV['VERSION']
|
45
|
+
version
|
46
|
+
else
|
47
|
+
::VERSION rescue Date.today.strftime("%Y.%m.%d")
|
48
|
+
end
|
49
|
+
|
50
|
+
# To release the monthly version do:
|
51
|
+
# $ PROJECT_VERSION=2009.03 rake release
|
52
|
+
|
53
|
+
PROJECT_FILES = FileList[`git ls-files`.split("\n")].exclude('.gitignore')
|
54
|
+
|
55
|
+
GEMSPEC = Gem::Specification.new{|s|
|
56
|
+
s.name = "mailit"
|
57
|
+
s.author = "Kevin Berry"
|
58
|
+
s.summary = "The Mailit library, by Kevin Berry"
|
59
|
+
s.description = "The Mailit library, by Kevin Berry"
|
60
|
+
s.email = "kevinberry@nrs.us"
|
61
|
+
s.homepage = "http://github.com/manveru/mailit"
|
62
|
+
s.platform = Gem::Platform::RUBY
|
63
|
+
s.version = PROJECT_VERSION
|
64
|
+
s.files = PROJECT_FILES
|
65
|
+
s.has_rdoc = true
|
66
|
+
s.require_path = "lib"
|
67
|
+
}
|
68
|
+
|
69
|
+
Dir.glob('tasks/*.rake'){|f| import(f) }
|
70
|
+
|
71
|
+
task :default => [:bacon]
|
72
|
+
|
73
|
+
CLEAN.include %w[
|
74
|
+
**/.*.sw?
|
75
|
+
*.gem
|
76
|
+
.config
|
77
|
+
**/*~
|
78
|
+
**/{data.db,cache.yaml}
|
79
|
+
*.yaml
|
80
|
+
pkg
|
81
|
+
rdoc
|
82
|
+
ydoc
|
83
|
+
*coverage*
|
84
|
+
]
|
data/lib/mailit.rb
ADDED
data/lib/mailit/mail.rb
ADDED
@@ -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, filename, 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.map{|key,value| "#{key}: #{value}"}.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
|