nmeans-pony 0.3.2

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.
Files changed (7) hide show
  1. data/README.rdoc +62 -0
  2. data/Rakefile +73 -0
  3. data/lib/pony.rb +100 -0
  4. data/pony.gemspec +19 -0
  5. data/spec/base.rb +4 -0
  6. data/spec/pony_spec.rb +139 -0
  7. metadata +60 -0
data/README.rdoc ADDED
@@ -0,0 +1,62 @@
1
+ = Pony, the express way to send email in Ruby
2
+
3
+ == Overview
4
+
5
+ Ruby no longer has to be jealous of PHP's mail() function, which can send an email in a single command.
6
+
7
+ Pony.mail(:to => 'you@example.com', :from => 'me@example.com', :subject => 'hi', :body => 'Hello there.')
8
+
9
+ Any option key may be omitted except for :to.
10
+
11
+ == Transport
12
+
13
+ Pony uses /usr/sbin/sendmail to send mail if it is available, otherwise it uses SMTP to localhost.
14
+
15
+ This can be over-ridden if you specify a via option
16
+
17
+ Pony.mail(:to => 'you@example.com', :via => :smtp) # sends via SMTP
18
+
19
+ Pony.mail(:to => 'you@example.com', :via => :sendmail) # sends via sendmail
20
+
21
+ You can also specify options for SMTP:
22
+
23
+ Pony.mail(:to => 'you@example.com', :via => :smtp, :smtp => {
24
+ :host => 'smtp.yourserver.com',
25
+ :port => '25',
26
+ :user => 'user',
27
+ :pass => 'pass',
28
+ :auth => :plain # :plain, :login, :cram_md5, no auth by default
29
+ :domain => "localhost.localdomain" # the HELO domain provided by the client to the server
30
+ }
31
+
32
+ == TLS/SSL
33
+
34
+ With smtp transport it also possible to use TLS/SSL:
35
+
36
+ Pony.mail(:to => 'you@example.com', :via => :smtp, :smtp => {
37
+ :host => 'smtp.gmail.com',
38
+ :port => '587',
39
+ :tls => true,
40
+ :user => 'user',
41
+ :pass => 'pass',
42
+ :auth => :plain # :plain, :login, :cram_md5, no auth by default
43
+ :domain => "localhost.localdomain" # the HELO domain provided by the client to the server
44
+ })
45
+
46
+ == Attachments
47
+
48
+ You can attach a file or two with the :attachments option:
49
+
50
+ Pony.mail(..., :attachments => {"foo.zip" => File.read("path/to/foo.zip"), "hello.txt" => "hello!"})
51
+
52
+ == Meta
53
+
54
+ Written by Adam Wiggins
55
+
56
+ Patches contributed by: Mathieu Martin, Arun Thampi, Thomas Hurst, Stephen
57
+ Celis, Othmane Benkirane, and Neil Mock
58
+
59
+ Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
60
+
61
+ http://github.com/adamwiggins/pony
62
+
data/Rakefile ADDED
@@ -0,0 +1,73 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ desc "Run all specs"
5
+ Spec::Rake::SpecTask.new('spec') do |t|
6
+ t.spec_files = FileList['spec/*_spec.rb']
7
+ end
8
+
9
+ desc "Print specdocs"
10
+ Spec::Rake::SpecTask.new(:doc) do |t|
11
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
12
+ t.spec_files = FileList['spec/*_spec.rb']
13
+ end
14
+
15
+ desc "Run all examples with RCov"
16
+ Spec::Rake::SpecTask.new('rcov') do |t|
17
+ t.spec_files = FileList['spec/*_spec.rb']
18
+ t.rcov = true
19
+ t.rcov_opts = ['--exclude', 'examples']
20
+ end
21
+
22
+ task :default => :spec
23
+
24
+ ######################################################
25
+
26
+ require 'rake'
27
+ require 'rake/testtask'
28
+ require 'rake/clean'
29
+ require 'rake/gempackagetask'
30
+ require 'fileutils'
31
+
32
+ version = "0.3"
33
+ name = "pony"
34
+
35
+ spec = Gem::Specification.new do |s|
36
+ s.name = name
37
+ s.version = version
38
+ s.summary = "Send email in one command: Pony.mail(:to => 'someone@example.com', :body => 'hello')"
39
+ s.description = "Send email in one command: Pony.mail(:to => 'someone@example.com', :body => 'hello')"
40
+ s.author = "Adam Wiggins"
41
+ s.email = "adam@heroku.com"
42
+ s.homepage = "http://github.com/adamwiggins/pony"
43
+ s.rubyforge_project = "pony"
44
+
45
+ s.platform = Gem::Platform::RUBY
46
+ s.has_rdoc = false
47
+
48
+ s.files = %w(Rakefile) + Dir.glob("{lib,spec}/**/*")
49
+
50
+ s.require_path = "lib"
51
+ s.add_dependency( 'tmail', '~> 1.0' )
52
+ end
53
+
54
+ Rake::GemPackageTask.new(spec) do |p|
55
+ p.need_tar = true if RUBY_PLATFORM !~ /mswin/
56
+ end
57
+
58
+ task :install => [ :package ] do
59
+ sh %{sudo gem install pkg/#{name}-#{version}.gem}
60
+ end
61
+
62
+ task :uninstall => [ :clean ] do
63
+ sh %{sudo gem uninstall #{name}}
64
+ end
65
+
66
+ Rake::TestTask.new do |t|
67
+ t.libs << "spec"
68
+ t.test_files = FileList['spec/*_spec.rb']
69
+ t.verbose = true
70
+ end
71
+
72
+ CLEAN.include [ 'pkg', '*.gem', '.config' ]
73
+
data/lib/pony.rb ADDED
@@ -0,0 +1,100 @@
1
+ require 'rubygems'
2
+ require 'net/smtp'
3
+ begin
4
+ require 'smtp_tls'
5
+ rescue LoadError
6
+ end
7
+ require 'base64'
8
+ begin
9
+ require 'tmail'
10
+ rescue LoadError
11
+ require 'actionmailer'
12
+ end
13
+
14
+ module Pony
15
+ def self.mail(options)
16
+ raise(ArgumentError, ":to is required") unless options[:to]
17
+
18
+ via = options.delete(:via)
19
+ if via.nil?
20
+ transport build_tmail(options)
21
+ else
22
+ if via_options.include?(via.to_s)
23
+ send("transport_via_#{via}", build_tmail(options), options)
24
+ else
25
+ raise(ArgumentError, ":via must be either smtp or sendmail")
26
+ end
27
+ end
28
+ end
29
+
30
+ def self.build_tmail(options)
31
+ mail = TMail::Mail.new
32
+ mail.to = options[:to]
33
+ mail.from = options[:from] || 'pony@unknown'
34
+ mail.subject = options[:subject]
35
+ if options[:attachments]
36
+ # If message has attachment, then body must be sent as a message part
37
+ # or it will not be interpreted correctly by client.
38
+ body = TMail::Mail.new
39
+ body.body = options[:body]
40
+ body.content_type = options[:content_type] || "text/plain"
41
+ mail.parts.push body
42
+ (options[:attachments] || []).each do |name, body|
43
+ attachment = TMail::Mail.new
44
+ attachment.transfer_encoding = "base64"
45
+ attachment.body = Base64.encode64(body)
46
+ # attachment.set_content_type # TODO: if necessary
47
+ attachment.set_content_disposition "attachment", "filename" => name
48
+ mail.parts.push attachment
49
+ end
50
+ else
51
+ mail.content_type = options[:content_type] || "text/plain"
52
+ mail.body = options[:body] || ""
53
+ end
54
+ puts mail
55
+ mail
56
+ end
57
+
58
+ def self.sendmail_binary
59
+ @sendmail_binary ||= `which sendmail`.chomp
60
+ end
61
+
62
+ def self.transport(tmail)
63
+ if File.executable? sendmail_binary
64
+ transport_via_sendmail(tmail)
65
+ else
66
+ transport_via_smtp(tmail)
67
+ end
68
+ end
69
+
70
+ def self.via_options
71
+ %w(sendmail smtp)
72
+ end
73
+
74
+ def self.transport_via_sendmail(tmail, options={})
75
+ IO.popen('-', 'w+') do |pipe|
76
+ if pipe
77
+ pipe.write(tmail.to_s)
78
+ else
79
+ exec(sendmail_binary, *tmail.to)
80
+ end
81
+ end
82
+ end
83
+
84
+ def self.transport_via_smtp(tmail, options={:smtp => {}})
85
+ default_options = {:smtp => { :host => 'localhost', :port => '25', :domain => 'localhost.localdomain' }}
86
+ o = default_options[:smtp].merge(options[:smtp])
87
+ smtp = Net::SMTP.new(o[:host], o[:port])
88
+ if o[:tls]
89
+ raise "You may need: gem install smtp_tls" unless smtp.respond_to?(:enable_starttls)
90
+ smtp.enable_starttls
91
+ end
92
+ if o.include?(:auth)
93
+ smtp.start(o[:domain], o[:user], o[:password], o[:auth])
94
+ else
95
+ smtp.start(o[:domain])
96
+ end
97
+ smtp.send_message tmail.to_s, tmail.from, tmail.to
98
+ smtp.finish
99
+ end
100
+ end
data/pony.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{pony}
5
+ s.version = "0.3.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Nickolas Means"]
9
+ s.date = %q{2009-07-10}
10
+ s.description = %q{hiroshi/pony + true multipart messages when sending attachments}
11
+ s.email = %q{nick@heliumsyndicate.com}
12
+ s.files = ["README.rdoc", "Rakefile", "lib/pony.rb", "pony.gemspec", "spec/base.rb", "spec/pony_spec.rb"]
13
+ s.has_rdoc = false
14
+ s.homepage = %q{http://github.com/nmeans/pony}
15
+ s.rdoc_options = ["--inline-source", "--charset=UTF-8"]
16
+ s.require_paths = ["lib"]
17
+ s.rubygems_version = %q{1.3.1}
18
+ s.summary = s.description
19
+ end
data/spec/base.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ require File.dirname(__FILE__) + '/../lib/pony'
data/spec/pony_spec.rb ADDED
@@ -0,0 +1,139 @@
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 "from" do
32
+ Pony.build_tmail(:from => 'joe@example.com').from.should == [ 'joe@example.com' ]
33
+ end
34
+
35
+ it "from (default)" do
36
+ Pony.build_tmail({}).from.should == [ 'pony@unknown' ]
37
+ end
38
+
39
+ it "subject" do
40
+ Pony.build_tmail(:subject => 'hello').subject.should == 'hello'
41
+ end
42
+
43
+ it "body" do
44
+ Pony.build_tmail(:body => 'What do you know, Joe?').body.should == 'What do you know, Joe?'
45
+ end
46
+
47
+ it "attachments" do
48
+ tmail = Pony.build_tmail(:attachments => {"foo.txt" => "content of foo.txt"})
49
+ tmail.should have(1).parts
50
+ tmail.parts.first.to_s.should == <<-PART
51
+ Content-Transfer-Encoding: Base64
52
+ Content-Disposition: attachment; filename=foo.txt
53
+
54
+ Y29udGVudCBvZiBmb28udHh0
55
+ PART
56
+ end
57
+ end
58
+
59
+ describe "transport" do
60
+ it "transports via the sendmail binary if it exists" do
61
+ File.stub!(:executable?).and_return(true)
62
+ Pony.should_receive(:transport_via_sendmail).with(:tmail)
63
+ Pony.transport(:tmail)
64
+ end
65
+
66
+ it "transports via smtp if no sendmail binary" do
67
+ Pony.stub!(:sendmail_binary).and_return('/does/not/exist')
68
+ Pony.should_receive(:transport_via_smtp).with(:tmail)
69
+ Pony.transport(:tmail)
70
+ end
71
+
72
+ it "transports mail via /usr/sbin/sendmail binary" do
73
+ pipe = mock('sendmail pipe')
74
+ IO.should_receive(:popen).with('-',"w+").and_yield(pipe)
75
+ pipe.should_receive(:write).with('message')
76
+ Pony.transport_via_sendmail(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'))
77
+ end
78
+
79
+ describe "SMTP transport" do
80
+ before do
81
+ @smtp = mock('net::smtp object')
82
+ @smtp.stub!(:start)
83
+ @smtp.stub!(:send_message)
84
+ @smtp.stub!(:finish)
85
+ Net::SMTP.stub!(:new).and_return(@smtp)
86
+ end
87
+
88
+ it "defaults to localhost as the SMTP server" do
89
+ Net::SMTP.should_receive(:new).with('localhost', '25').and_return(@smtp)
90
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'))
91
+ end
92
+
93
+ it "uses SMTP authorization when auth key is provided" do
94
+ o = { :smtp => { :user => 'user', :password => 'password', :auth => 'plain'}}
95
+ @smtp.should_receive(:start).with('localhost.localdomain', 'user', 'password', 'plain')
96
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'), o)
97
+ end
98
+
99
+ it "enable starttls when tls option is true" do
100
+ o = { :smtp => { :user => 'user', :password => 'password', :auth => 'plain', :tls => true}}
101
+ @smtp.should_receive(:enable_starttls)
102
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'), o)
103
+ end
104
+
105
+ it "starts the job" do
106
+ @smtp.should_receive(:start)
107
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'))
108
+ end
109
+
110
+ it "sends a tmail message" do
111
+ @smtp.should_receive(:send_message)
112
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'))
113
+ end
114
+
115
+ it "finishes the job" do
116
+ @smtp.should_receive(:finish)
117
+ Pony.transport_via_smtp(mock('tmail', :to => 'to', :from => 'from', :to_s => 'message'))
118
+ end
119
+
120
+ end
121
+ end
122
+
123
+ describe ":via option should over-ride the default transport mechanism" do
124
+ it "should send via sendmail if :via => sendmail" do
125
+ Pony.should_receive(:transport_via_sendmail)
126
+ Pony.mail(:to => 'joe@example.com', :via => :sendmail)
127
+ end
128
+
129
+ it "should send via smtp if :via => smtp" do
130
+ Pony.should_receive(:transport_via_smtp)
131
+ Pony.mail(:to => 'joe@example.com', :via => :smtp)
132
+ end
133
+
134
+ it "should raise an error if via is neither smtp nor sendmail" do
135
+ lambda { Pony.mail(:to => 'joe@plumber.com', :via => :pigeon) }.should raise_error(ArgumentError)
136
+ end
137
+ end
138
+
139
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nmeans-pony
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.2
5
+ platform: ruby
6
+ authors:
7
+ - Nickolas Means
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-10 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: hiroshi/pony + true multipart messages when sending attachments
17
+ email: nick@heliumsyndicate.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README.rdoc
26
+ - Rakefile
27
+ - lib/pony.rb
28
+ - pony.gemspec
29
+ - spec/base.rb
30
+ - spec/pony_spec.rb
31
+ has_rdoc: false
32
+ homepage: http://github.com/nmeans/pony
33
+ licenses:
34
+ post_install_message:
35
+ rdoc_options:
36
+ - --inline-source
37
+ - --charset=UTF-8
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ requirements: []
53
+
54
+ rubyforge_project:
55
+ rubygems_version: 1.3.5
56
+ signing_key:
57
+ specification_version: 2
58
+ summary: hiroshi/pony + true multipart messages when sending attachments
59
+ test_files: []
60
+