actionmailer 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionmailer might be problematic. Click here for more details.
- data/CHANGELOG +5 -0
- data/README +36 -0
- data/lib/action_mailer.rb +1 -1
- data/lib/action_mailer/base.rb +6 -1
- data/lib/action_mailer/vendor/tmail/attachments.rb +31 -0
- data/lib/action_mailer/vendor/tmail/facade.rb +1 -0
- data/lib/action_mailer/vendor/tmail/mail.rb +3 -1
- data/lib/action_mailer/vendor/tmail/quoting.rb +83 -0
- data/rakefile +2 -2
- data/test/mail_service_test.rb +16 -0
- metadata +6 -4
data/CHANGELOG
CHANGED
data/README
CHANGED
@@ -5,6 +5,12 @@ are used to consolidate code for sending out forgotten passwords, welcoming
|
|
5
5
|
wishes on signup, invoices for billing, and any other use case that requires
|
6
6
|
a written notification to either a person or another system.
|
7
7
|
|
8
|
+
Additionally, an Action Mailer class can be used to process incoming email,
|
9
|
+
such as allowing a weblog to accept new posts from an email (which could even
|
10
|
+
have been sent from a phone).
|
11
|
+
|
12
|
+
== Sending emails
|
13
|
+
|
8
14
|
The framework works by setting up all the email details, except the body,
|
9
15
|
in methods on the service layer. Subject, recipients, sender, and timestamp
|
10
16
|
are all set up this way. An example of such a method:
|
@@ -47,6 +53,36 @@ ApplicationMailer, it would look like this:
|
|
47
53
|
ApplicationMailer.deliver_signed_up("david@loudthinking.com") # sends the email
|
48
54
|
ApplicationMailer.new.signed_up("david@loudthinking.com") # won't work!
|
49
55
|
|
56
|
+
== Receiving emails
|
57
|
+
|
58
|
+
To receive emails, you need to implement a public instance method called receive that takes a
|
59
|
+
tmail object as its single parameter. The Action Mailer framework has a corresponding class method,
|
60
|
+
which is also called receive, that accepts a raw, unprocessed email as a string, which it then turns
|
61
|
+
into the tmail object and calls the receive instance method.
|
62
|
+
|
63
|
+
Example:
|
64
|
+
|
65
|
+
class Mailman < ActionMailer::Base
|
66
|
+
def receive(email)
|
67
|
+
page = Page.find_by_address(email.to.first)
|
68
|
+
page.emails.create(
|
69
|
+
:subject => email.subject, :body => email.body
|
70
|
+
)
|
71
|
+
|
72
|
+
if email.has_attachments?
|
73
|
+
for attachment in email.attachments
|
74
|
+
page.attachments.create({
|
75
|
+
:file => attachment, :description => email.subject
|
76
|
+
})
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
This Mailman can be the target for Postfix. In Rails, you would use the runner like this:
|
83
|
+
|
84
|
+
./script/runner 'Mailman.receive(STDIN.read)'
|
85
|
+
|
50
86
|
|
51
87
|
== Dependencies
|
52
88
|
|
data/lib/action_mailer.rb
CHANGED
data/lib/action_mailer/base.rb
CHANGED
@@ -114,7 +114,7 @@ module ActionMailer #:nodoc:
|
|
114
114
|
rescue Object => e
|
115
115
|
raise e if raise_delivery_errors
|
116
116
|
end
|
117
|
-
end
|
117
|
+
end
|
118
118
|
end
|
119
119
|
|
120
120
|
def mail(to, subject, body, from, timestamp = nil, headers = {},
|
@@ -150,6 +150,11 @@ module ActionMailer #:nodoc:
|
|
150
150
|
"=?#{charset}?Q?#{text}?="
|
151
151
|
end
|
152
152
|
|
153
|
+
def receive(raw_email)
|
154
|
+
logger.info "Received mail:\n #{raw_email}" unless logger.nil?
|
155
|
+
new.receive(TMail::Mail.parse(raw_email))
|
156
|
+
end
|
157
|
+
|
153
158
|
private
|
154
159
|
def perform_delivery_smtp(mail)
|
155
160
|
Net::SMTP.start(server_settings[:address], server_settings[:port], server_settings[:domain],
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module TMail
|
4
|
+
class Attachment < StringIO
|
5
|
+
attr_accessor :original_filename, :content_type
|
6
|
+
end
|
7
|
+
|
8
|
+
class Mail
|
9
|
+
def has_attachments?
|
10
|
+
multipart? && parts.any? { |part| part.header["content-type"].main_type != "text" }
|
11
|
+
end
|
12
|
+
|
13
|
+
def attachments
|
14
|
+
if multipart?
|
15
|
+
parts.collect { |part|
|
16
|
+
if part.header["content-type"].main_type != "text"
|
17
|
+
content = part.body.unpack("m")[0]
|
18
|
+
content = part.body if content.blank?
|
19
|
+
file_name = part.header["content-type"].params["name"]
|
20
|
+
|
21
|
+
next if file_name.blank? || content.blank?
|
22
|
+
|
23
|
+
attachment = Attachment.new(content)
|
24
|
+
attachment.original_filename = file_name.strip.dup
|
25
|
+
attachment
|
26
|
+
end
|
27
|
+
}.compact
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -14,6 +14,8 @@ require 'tmail/header'
|
|
14
14
|
require 'tmail/port'
|
15
15
|
require 'tmail/config'
|
16
16
|
require 'tmail/utils'
|
17
|
+
require 'tmail/attachments'
|
18
|
+
require 'tmail/quoting'
|
17
19
|
require 'socket'
|
18
20
|
|
19
21
|
|
@@ -320,7 +322,7 @@ module TMail
|
|
320
322
|
body_port().ropen {|f| f.each(&block) }
|
321
323
|
end
|
322
324
|
|
323
|
-
def
|
325
|
+
def quoted_body
|
324
326
|
parse_body
|
325
327
|
@body_port.ropen {|f|
|
326
328
|
return f.read
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'iconv'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module TMail
|
5
|
+
class Mail
|
6
|
+
def subject(to_charset = 'utf-8')
|
7
|
+
Unquoter.unquote_and_convert_to(quoted_subject, to_charset)
|
8
|
+
end
|
9
|
+
|
10
|
+
def unquoted_body(to_charset = 'utf-8')
|
11
|
+
Unquoter.unquote_and_convert_to(quoted_body, to_charset, header["content-type"]["charset"])
|
12
|
+
end
|
13
|
+
|
14
|
+
def body(to_charset = 'utf-8', &block)
|
15
|
+
attachment_presenter = block || Proc.new { |file_name| "Attachment: #{file_name}\n" }
|
16
|
+
|
17
|
+
if multipart?
|
18
|
+
parts.collect { |part|
|
19
|
+
part.header["content-type"].main_type == "text" ?
|
20
|
+
part.unquoted_body(to_charset) :
|
21
|
+
attachment_presenter.call(part.header["content-type"].params["name"])
|
22
|
+
}.join
|
23
|
+
else
|
24
|
+
unquoted_body(to_charset)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Unquoter
|
30
|
+
class << self
|
31
|
+
def unquote_and_convert_to(text, to_charset, from_charset = "iso-8859-1")
|
32
|
+
return "" if text.nil?
|
33
|
+
if text =~ /^=\?(.*?)\?(.)\?(.*)\?=$/
|
34
|
+
from_charset = $1
|
35
|
+
quoting_method = $2
|
36
|
+
text = $3
|
37
|
+
case quoting_method
|
38
|
+
when "Q" then
|
39
|
+
unquote_quoted_printable_and_convert_to(text, from_charset, to_charset)
|
40
|
+
when "B" then
|
41
|
+
unquote_base64_and_convert_to(text, from_charset, to_charset)
|
42
|
+
else
|
43
|
+
raise "unknown quoting method #{quoting_method.inspect}"
|
44
|
+
end
|
45
|
+
else
|
46
|
+
unquote_quoted_printable_and_convert_to(text, from_charset, to_charset)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def unquote_quoted_printable_and_convert_to(text, from, to)
|
51
|
+
text ? Iconv.iconv(to, from || "ISO-8859-1", text.gsub(/_/," ").unpack("M*").first).first : ""
|
52
|
+
end
|
53
|
+
|
54
|
+
def unquote_base64_and_convert_to(text, from, to)
|
55
|
+
text ? Iconv.iconv(to, from || "ISO-8859-1", Base64.decode64(text)).first : ""
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if __FILE__ == $0
|
62
|
+
require 'test/unit'
|
63
|
+
|
64
|
+
class TC_Unquoter < Test::Unit::TestCase
|
65
|
+
def test_unquote_quoted_printable
|
66
|
+
a ="=?ISO-8859-1?Q?[166417]_Bekr=E6ftelse_fra_Rejsefeber?="
|
67
|
+
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
68
|
+
assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_unquote_base64
|
72
|
+
a ="=?ISO-8859-1?B?WzE2NjQxN10gQmVrcuZmdGVsc2UgZnJhIFJlanNlZmViZXI=?="
|
73
|
+
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
74
|
+
assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_unquote_without_charset
|
78
|
+
a ="[166417]_Bekr=E6ftelse_fra_Rejsefeber"
|
79
|
+
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
80
|
+
assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/rakefile
CHANGED
@@ -8,7 +8,7 @@ require 'rake/contrib/rubyforgepublisher'
|
|
8
8
|
|
9
9
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
10
10
|
PKG_NAME = 'actionmailer'
|
11
|
-
PKG_VERSION = '0.
|
11
|
+
PKG_VERSION = '0.8.0' + PKG_BUILD
|
12
12
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
13
13
|
|
14
14
|
desc "Default Task"
|
@@ -50,7 +50,7 @@ spec = Gem::Specification.new do |s|
|
|
50
50
|
s.rubyforge_project = "actionmailer"
|
51
51
|
s.homepage = "http://www.rubyonrails.org"
|
52
52
|
|
53
|
-
s.add_dependency('actionpack', '= 1.
|
53
|
+
s.add_dependency('actionpack', '= 1.6.0' + PKG_BUILD)
|
54
54
|
|
55
55
|
s.has_rdoc = true
|
56
56
|
s.requirements << 'none'
|
data/test/mail_service_test.rb
CHANGED
@@ -212,5 +212,21 @@ class ActionMailerTest < Test::Unit::TestCase
|
|
212
212
|
assert_equal 1, ActionMailer::Base.deliveries.size
|
213
213
|
end
|
214
214
|
|
215
|
+
def test_unquote_subject
|
216
|
+
msg = <<EOF
|
217
|
+
From: me@example.com
|
218
|
+
Subject: =?utf-8?Q?testing_testing_=D6=A4?=
|
219
|
+
Content-Type: text/plain; charset=iso-8859-1
|
220
|
+
|
221
|
+
This_is_a_test
|
222
|
+
2 + 2 =3D 4
|
223
|
+
EOF
|
224
|
+
mail = TMail::Mail.parse(msg)
|
225
|
+
assert_equal "testing testing \326\244", mail.subject
|
226
|
+
assert_equal "=?utf-8?Q?testing_testing_=D6=A4?=", mail.quoted_subject
|
227
|
+
assert_equal "This is a test\n2 + 2 = 4\n", mail.body
|
228
|
+
assert_equal "This_is_a_test\n2 + 2 =3D 4\n", mail.quoted_body
|
229
|
+
end
|
230
|
+
|
215
231
|
end
|
216
232
|
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.
|
2
|
+
rubygems_version: 0.8.8
|
3
3
|
specification_version: 1
|
4
4
|
name: actionmailer
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2005-03-
|
6
|
+
version: 0.8.0
|
7
|
+
date: 2005-03-22
|
8
8
|
summary: Service layer for easy email delivery and testing.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- lib/action_mailer/vendor/tmail.rb
|
43
43
|
- lib/action_mailer/vendor/text/format.rb
|
44
44
|
- lib/action_mailer/vendor/tmail/address.rb
|
45
|
+
- lib/action_mailer/vendor/tmail/attachments.rb
|
45
46
|
- lib/action_mailer/vendor/tmail/base64.rb
|
46
47
|
- lib/action_mailer/vendor/tmail/config.rb
|
47
48
|
- lib/action_mailer/vendor/tmail/encode.rb
|
@@ -56,6 +57,7 @@ files:
|
|
56
57
|
- lib/action_mailer/vendor/tmail/obsolete.rb
|
57
58
|
- lib/action_mailer/vendor/tmail/parser.rb
|
58
59
|
- lib/action_mailer/vendor/tmail/port.rb
|
60
|
+
- lib/action_mailer/vendor/tmail/quoting.rb
|
59
61
|
- lib/action_mailer/vendor/tmail/scanner.rb
|
60
62
|
- lib/action_mailer/vendor/tmail/scanner_r.rb
|
61
63
|
- lib/action_mailer/vendor/tmail/stringio.rb
|
@@ -83,5 +85,5 @@ dependencies:
|
|
83
85
|
-
|
84
86
|
- "="
|
85
87
|
- !ruby/object:Gem::Version
|
86
|
-
version: 1.
|
88
|
+
version: 1.6.0
|
87
89
|
version:
|