pony 1.0 → 1.0.1

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.
@@ -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: []