pony 1.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -81,6 +81,7 @@ Options passed pretty much directly to Mail
81
81
  attachments # see Attachments section above
82
82
  headers # see Custom headers section above
83
83
  message_id
84
+ sender
84
85
 
85
86
  Other options
86
87
  via # :smtp or :sendmail, see Transport section above
@@ -85,6 +85,7 @@ require 'base64'
85
85
  # attachments # see Attachments section above
86
86
  # headers # see Custom headers section above
87
87
  # message_id
88
+ # sender # Sets "envelope from" (and the Sender header)
88
89
  #
89
90
  # Other options
90
91
  # via # :smtp or :sendmail, see Transport section above
@@ -155,6 +156,7 @@ module Pony
155
156
  subject options[:subject]
156
157
  date options[:date] || Time.now
157
158
  message_id options[:message_id]
159
+ sender options[:sender] if options[:sender]
158
160
 
159
161
  if options[:html_body]
160
162
  html_part do
@@ -0,0 +1,110 @@
1
+ require 'rubygems'
2
+ require 'net/smtp'
3
+ require 'mime/types'
4
+ begin
5
+ require 'smtp_tls'
6
+ rescue LoadError
7
+ end
8
+ require 'base64'
9
+ begin
10
+ require 'tmail'
11
+ rescue LoadError
12
+ require 'actionmailer'
13
+ end
14
+
15
+ module Pony
16
+ def self.mail(options)
17
+ raise(ArgumentError, ":to is required") unless options[:to]
18
+
19
+ via = options.delete(:via)
20
+ if via.nil?
21
+ transport build_tmail(options)
22
+ else
23
+ if via_options.include?(via.to_s)
24
+ send("transport_via_#{via}", build_tmail(options), options)
25
+ else
26
+ raise(ArgumentError, ":via must be either smtp or sendmail")
27
+ end
28
+ end
29
+ end
30
+
31
+ def self.build_tmail(options)
32
+ mail = TMail::Mail.new
33
+ mail.to = options[:to]
34
+ mail.cc = options[:cc]
35
+ mail.bcc = options[:bcc]
36
+ mail.from = options[:from] || 'pony@unknown'
37
+ mail.subject = options[:subject]
38
+ mail.date = options[:date] || Time.now
39
+ mail.message_id = options[:message_id]
40
+ if options[:attachments]
41
+ # If message has attachment, then body must be sent as a message part
42
+ # or it will not be interpreted correctly by client.
43
+ body = TMail::Mail.new
44
+ body.body = options[:body] || ""
45
+ body.content_type = options[:content_type] || "text/plain"
46
+ mail.parts.push body
47
+ (options[:attachments] || []).each do |name, body|
48
+ attachment = TMail::Mail.new
49
+ attachment.transfer_encoding = "base64"
50
+ attachment.body = Base64.encode64(body)
51
+ content_type = MIME::Types.type_for(name).to_s
52
+ attachment.content_type = content_type unless content_type == ""
53
+ attachment.set_content_disposition "attachment", "filename" => name
54
+ mail.parts.push attachment
55
+ end
56
+ else
57
+ mail.content_type = options[:content_type] || "text/plain"
58
+ mail.body = options[:body] || ""
59
+ end
60
+ (options[:headers] ||= {}).each do |key, value|
61
+ mail[key] = value
62
+ end
63
+ mail.charset = options[:charset] # charset must be set after setting content_type
64
+ mail
65
+ end
66
+
67
+ def self.sendmail_binary
68
+ sendmail = `which sendmail`.chomp
69
+ sendmail.empty? ? '/usr/sbin/sendmail' : sendmail
70
+ end
71
+
72
+ def self.transport(tmail)
73
+ if File.executable? sendmail_binary
74
+ transport_via_sendmail(tmail)
75
+ else
76
+ transport_via_smtp(tmail)
77
+ end
78
+ end
79
+
80
+ def self.via_options
81
+ %w(sendmail smtp)
82
+ end
83
+
84
+ def self.transport_via_sendmail(tmail, options={})
85
+ IO.popen('-', 'w+') do |pipe|
86
+ if pipe
87
+ pipe.write(tmail.to_s)
88
+ else
89
+ exec(sendmail_binary, "-t")
90
+ end
91
+ end
92
+ end
93
+
94
+ def self.transport_via_smtp(tmail, options={:smtp => {}})
95
+ default_options = {:smtp => { :host => 'localhost', :port => '25', :domain => 'localhost.localdomain' }}
96
+ o = default_options[:smtp].merge(options[:smtp])
97
+ smtp = Net::SMTP.new(o[:host], o[:port])
98
+ if o[:tls]
99
+ raise "You may need: gem install smtp_tls" unless smtp.respond_to?(:enable_starttls)
100
+ smtp.enable_starttls
101
+ end
102
+ if o.include?(:auth)
103
+ smtp.start(o[:domain], o[:user], o[:password], o[:auth])
104
+ else
105
+ smtp.start(o[:domain])
106
+ end
107
+ smtp.send_message tmail.to_s, tmail.from, tmail.destinations
108
+ smtp.finish
109
+ end
110
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{pony}
5
- s.version = "1.0"
5
+ s.version = "1.0.1"
6
6
 
7
7
  s.description = "Send email in one command: Pony.mail(:to => 'someone@example.com', :body => 'hello')"
8
8
  s.summary = s.description
@@ -118,6 +118,10 @@ describe Pony do
118
118
  Pony.build_mail(:headers => {"List-ID" => "<abc@def.com>"})['List-ID'].to_s.should == '<abc@def.com>'
119
119
  end
120
120
 
121
+ it "sender" do
122
+ Pony.build_mail(:sender => "abc@def.com")['Sender'].to_s.should == 'abc@def.com'
123
+ end
124
+
121
125
  it "utf-8 encoded subject line" do
122
126
  mail = Pony.build_mail(:to => 'btp@foo', :subject => 'Café', :body => 'body body body')
123
127
  mail['subject'].encoded.should =~ /^Subject: =\?UTF-8/;
@@ -0,0 +1,232 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe Pony do
4
+ it "sends mail" do
5
+ Pony.should_receive(:transport) do |tmail|
6
+ tmail.to.should == [ 'joe@example.com' ]
7
+ tmail.from.should == [ 'sender@example.com' ]
8
+ tmail.subject.should == 'hi'
9
+ tmail.body.should == 'Hello, Joe.'
10
+ end
11
+ Pony.mail(:to => 'joe@example.com', :from => 'sender@example.com', :subject => 'hi', :body => 'Hello, Joe.')
12
+ end
13
+
14
+ it "requires :to param" do
15
+ Pony.stub!(:transport)
16
+ lambda { Pony.mail({}) }.should raise_error(ArgumentError)
17
+ end
18
+
19
+ it "doesn't require any other param" do
20
+ Pony.stub!(:transport)
21
+ lambda { Pony.mail(:to => 'joe@example.com') }.should_not raise_error
22
+ end
23
+
24
+ ####################
25
+
26
+ describe "builds a TMail object with field:" do
27
+ it "to" do
28
+ Pony.build_tmail(:to => 'joe@example.com').to.should == [ 'joe@example.com' ]
29
+ end
30
+
31
+ it "to with multiple recipients" do
32
+ Pony.build_tmail(:to => 'joe@example.com, friedrich@example.com').to.should == [ 'joe@example.com', 'friedrich@example.com' ]
33
+ end
34
+
35
+ it "to with multiple recipients and names" do
36
+ Pony.build_tmail(:to => 'joe@example.com, "Friedrich Hayek" <friedrich@example.com>').to.should == [ 'joe@example.com', 'friedrich@example.com' ]
37
+ end
38
+
39
+ it "to with multiple recipients and names in an array" do
40
+ Pony.build_tmail(:to => ['joe@example.com', '"Friedrich Hayek" <friedrich@example.com>']).to.should == [ 'joe@example.com', 'friedrich@example.com' ]
41
+ end
42
+
43
+ it "cc" do
44
+ Pony.build_tmail(:cc => 'joe@example.com').cc.should == [ 'joe@example.com' ]
45
+ end
46
+
47
+ it "cc with multiple recipients" do
48
+ Pony.build_tmail(:cc => 'joe@example.com, friedrich@example.com').cc.should == [ 'joe@example.com', 'friedrich@example.com' ]
49
+ end
50
+
51
+ it "from" do
52
+ Pony.build_tmail(:from => 'joe@example.com').from.should == [ 'joe@example.com' ]
53
+ end
54
+
55
+ it "bcc" do
56
+ Pony.build_tmail(:bcc => 'joe@example.com').bcc.should == [ 'joe@example.com' ]
57
+ end
58
+
59
+ it "bcc with multiple recipients" do
60
+ Pony.build_tmail(:bcc => 'joe@example.com, friedrich@example.com').bcc.should == [ 'joe@example.com', 'friedrich@example.com' ]
61
+ end
62
+
63
+ it "charset" do
64
+ Pony.build_tmail(:charset => 'UTF-8').charset.should == 'UTF-8'
65
+ end
66
+
67
+ it "default charset" do
68
+ Pony.build_tmail(:body => 'body').charset.should == nil
69
+ Pony.build_tmail(:body => 'body', :content_type => 'text/html').charset.should == nil
70
+ end
71
+
72
+ it "from (default)" do
73
+ Pony.build_tmail({}).from.should == [ 'pony@unknown' ]
74
+ end
75
+
76
+ it "subject" do
77
+ Pony.build_tmail(:subject => 'hello').subject.should == 'hello'
78
+ end
79
+
80
+ it "body" do
81
+ Pony.build_tmail(:body => 'What do you know, Joe?').body.should == 'What do you know, Joe?'
82
+ end
83
+
84
+ it "content_type" do
85
+ Pony.build_tmail(:content_type => 'text/html').content_type.should == 'text/html'
86
+ end
87
+
88
+ it "message_id" do
89
+ Pony.build_tmail(:message_id => '<abc@def.com>').message_id.should == '<abc@def.com>'
90
+ end
91
+
92
+ it "custom headers" do
93
+ Pony.build_tmail(:headers => {"List-ID" => "<abc@def.com>"})['List-ID'].to_s.should == '<abc@def.com>'
94
+ end
95
+
96
+ it "attachments" do
97
+ tmail = Pony.build_tmail(:attachments => {"foo.txt" => "content of foo.txt"})
98
+ tmail.should have(2).parts
99
+ tmail.parts.first.to_s.should == "Content-Type: text/plain\n\n"
100
+ tmail.parts.last.to_s.should == <<-PART
101
+ Content-Type: text/plain
102
+ Content-Transfer-Encoding: Base64
103
+ Content-Disposition: attachment; filename=foo.txt
104
+
105
+ Y29udGVudCBvZiBmb28udHh0
106
+ PART
107
+ end
108
+
109
+ it "suggests mime-type" do
110
+ tmail = Pony.build_tmail(:attachments => {"foo.pdf" => "content of foo.pdf"})
111
+ tmail.should have(2).parts
112
+ tmail.parts.first.to_s.should == "Content-Type: text/plain\n\n"
113
+ tmail.parts.last.to_s.should == <<-PART
114
+ Content-Type: application/pdf
115
+ Content-Transfer-Encoding: Base64
116
+ Content-Disposition: attachment; filename=foo.pdf
117
+
118
+ Y29udGVudCBvZiBmb28ucGRm
119
+ PART
120
+ end
121
+ end
122
+
123
+ describe "transport" do
124
+ it "transports via the sendmail binary if it exists" do
125
+ File.stub!(:executable?).and_return(true)
126
+ Pony.should_receive(:transport_via_sendmail).with(:tmail)
127
+ Pony.transport(:tmail)
128
+ end
129
+
130
+ it "transports via smtp if no sendmail binary" do
131
+ Pony.stub!(:sendmail_binary).and_return('/does/not/exist')
132
+ Pony.should_receive(:transport_via_smtp).with(:tmail)
133
+ Pony.transport(:tmail)
134
+ end
135
+
136
+ it "transports mail via /usr/sbin/sendmail binary" do
137
+ pipe = mock('sendmail pipe')
138
+ IO.should_receive(:popen).with('-',"w+").and_yield(pipe)
139
+ pipe.should_receive(:write).with('message')
140
+ Pony.transport_via_sendmail(mock('tmail', :to => ['to'], :from => ['from'], :to_s => 'message'))
141
+ end
142
+
143
+ describe "SMTP transport" do
144
+ before do
145
+ @smtp = mock('net::smtp object')
146
+ @smtp.stub!(:start)
147
+ @smtp.stub!(:send_message)
148
+ @smtp.stub!(:finish)
149
+ Net::SMTP.stub!(:new).and_return(@smtp)
150
+ end
151
+
152
+ it "passes cc and bcc as the list of recipients" do
153
+ @smtp.should_receive(:send_message).with("message", ['from'], ['to', 'cc', 'bcc'])
154
+ Pony.transport_via_smtp(mock('tmail', :to => ['to'], :cc => ['cc'], :from => ['from'], :to_s => 'message', :bcc => ['bcc'], :destinations => ['to', 'cc', 'bcc']))
155
+ @smtp.should_receive(:send_message).with("message", 'from', ['to', 'cc'])
156
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :cc => 'cc', :from => 'from', :to_s => 'message', :bcc => nil, :destinations => ['to', 'cc']))
157
+ end
158
+
159
+ it "only pass cc as the list of recipients" do
160
+ @smtp.should_receive(:send_message).with("message", ['from'], ['to', 'cc' ])
161
+ Pony.transport_via_smtp(mock('tmail', :to => ['to'], :cc => ['cc'], :from => ['from'], :to_s => 'message', :bcc => nil, :destinations => ['to', 'cc']))
162
+ end
163
+
164
+ it "only pass bcc as the list of recipients" do
165
+ @smtp.should_receive(:send_message).with("message", ['from'], ['to', 'bcc' ])
166
+ Pony.transport_via_smtp(mock('tmail', :to => ['to'], :cc => nil, :from => ['from'], :to_s => 'message', :bcc => ['bcc'], :destinations => ['to', 'bcc']))
167
+ end
168
+
169
+ it "passes cc and bcc as the list of recipients when there are a few of them" do
170
+ @smtp.should_receive(:send_message).with("message", ['from'], ['to', 'to2', 'cc', 'bcc', 'bcc2', 'bcc3'])
171
+ Pony.transport_via_smtp(mock('tmail', :to => ['to', 'to2'], :cc => ['cc'], :from => ['from'], :to_s => 'message', :bcc => ['bcc', 'bcc2', 'bcc3'], :destinations => ['to', 'to2', 'cc', 'bcc', 'bcc2', 'bcc3']))
172
+ end
173
+
174
+ it "defaults to localhost as the SMTP server" do
175
+ Net::SMTP.should_receive(:new).with('localhost', '25').and_return(@smtp)
176
+ Pony.transport_via_smtp(mock('tmail', :to => ['to'], :from => ['from'], :to_s => 'message', :cc => nil, :bcc => nil, :destinations => ['to']))
177
+ end
178
+
179
+ it "uses SMTP authorization when auth key is provided" do
180
+ o = { :smtp => { :user => 'user', :password => 'password', :auth => 'plain'}}
181
+ @smtp.should_receive(:start).with('localhost.localdomain', 'user', 'password', 'plain')
182
+ Pony.transport_via_smtp(mock('tmail', :to => ['to'], :from => ['from'], :to_s => 'message', :cc => nil, :bcc => nil, :destinations => ['to']), o)
183
+ end
184
+
185
+ it "enable starttls when tls option is true" do
186
+ o = { :smtp => { :user => 'user', :password => 'password', :auth => 'plain', :tls => true}}
187
+ @smtp.should_receive(:enable_starttls)
188
+ Pony.transport_via_smtp(mock('tmail', :to => ['to'], :from => ['from'], :to_s => 'message', :cc => nil, :bcc => nil, :destinations => ['to']), o)
189
+ end
190
+
191
+ it "starts the job" do
192
+ @smtp.should_receive(:start)
193
+ Pony.transport_via_smtp(mock('tmail', :to => ['to'], :from => ['from'], :to_s => 'message', :cc => nil, :bcc => nil, :destinations => ['to']))
194
+ end
195
+
196
+ it "sends a tmail message" do
197
+ @smtp.should_receive(:send_message)
198
+ Pony.transport_via_smtp(mock('tmail', :to => ['to'], :from => ['from'], :to_s => 'message', :cc => nil, :bcc => nil, :destinations => ['to']))
199
+ end
200
+
201
+ it "finishes the job" do
202
+ @smtp.should_receive(:finish)
203
+ Pony.transport_via_smtp(mock('tmail', :to => ['to'], :from => ['from'], :to_s => 'message', :cc => nil, :bcc => nil, :destinations => ['to']))
204
+ end
205
+
206
+ end
207
+ end
208
+
209
+ describe ":via option should over-ride the default transport mechanism" do
210
+ it "should send via sendmail if :via => sendmail" do
211
+ Pony.should_receive(:transport_via_sendmail)
212
+ Pony.mail(:to => 'joe@example.com', :via => :sendmail)
213
+ end
214
+
215
+ it "should send via smtp if :via => smtp" do
216
+ Pony.should_receive(:transport_via_smtp)
217
+ Pony.mail(:to => 'joe@example.com', :via => :smtp)
218
+ end
219
+
220
+ it "should raise an error if via is neither smtp nor sendmail" do
221
+ lambda { Pony.mail(:to => 'joe@plumber.com', :via => :pigeon) }.should raise_error(ArgumentError)
222
+ end
223
+ end
224
+
225
+ describe "sendmail binary location" do
226
+ it "should default to /usr/sbin/sendmail if not in path" do
227
+ Pony.stub!(:'`').and_return('')
228
+ Pony.sendmail_binary.should == '/usr/sbin/sendmail'
229
+ end
230
+ end
231
+
232
+ end
metadata CHANGED
@@ -5,7 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- version: "1.0"
8
+ - 1
9
+ version: 1.0.1
9
10
  platform: ruby
10
11
  authors:
11
12
  - Adam Wiggins
@@ -14,7 +15,7 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-05-07 00:00:00 -06:00
18
+ date: 2010-09-02 00:00:00 -07:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
@@ -42,9 +43,11 @@ files:
42
43
  - README.rdoc
43
44
  - Rakefile
44
45
  - pony.gemspec
46
+ - lib/pony.rb~
45
47
  - lib/pony.rb
46
- - spec/pony_spec.rb
47
48
  - spec/base.rb
49
+ - spec/pony_spec.rb~
50
+ - spec/pony_spec.rb
48
51
  has_rdoc: true
49
52
  homepage: http://github.com/benprew/pony
50
53
  licenses: []