ruby-qmail 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Allen Fair
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,66 @@
1
+ = ruby-qmail
2
+
3
+ The RubyQmail Plugin provides support for the Qmail MTA and helpers for creating data-aware applications
4
+ While initially intended to operate in a large-scale Qmail environment, some of these features may be useful for
5
+ applications on other platforms. In fact, this plugin is not required if you are using Qmail because
6
+ ActionMailer's sendmail and smtp configurations will work for simple Qmail installations.
7
+
8
+ NOTE: This is still in an early stage of development, but has been tested to insert email into the qmail queue
9
+ via the qmail-queue and QMQP protocols.
10
+
11
+ == Using ruby-qmail
12
+
13
+ Ruby Qmail takes a message in 3 parts
14
+ * The envelope return path. This is not necessarily the same as the From: header, and is the email address to which
15
+ bounces will be sent. This should most likely be a special address used to identify the mailing being sent,
16
+ containing the message number or other identifier, and perhaps the source of the message. For example:
17
+ bounces-messageid@example.com
18
+ Ruby-Qmail used VERP (Variable Envelope Return Path) by default, so bounces will be returned in the form
19
+ bounces-messageid-recipientmailbox=recipientdomain@example.com
20
+ for individual returns. Qmail will also send a report to the return path (without the recipient address encoded)
21
+ bounces-messageid-@example.com
22
+ with addresses and error messages for all undeliverable addresses.
23
+ * Recipient List. This is either a String containing an email address (only the user@domain part), an array of
24
+ email addresses, or a file of email addresses (one per line), or any other object implementing Enumerable.
25
+ * Message Data. This is a String or Filename of a raw RFC822 message, with full message headers, body parts and
26
+ attachments, ususally composed via Tmail or Rmail.
27
+
28
+ Call the insert command
29
+ RubyQmail::Queue.insert "bounces-123@example.com", ['recipient@email.com',...], message_file
30
+ The call returns true if the message was inserted. If you want more control and information, you can run it as:
31
+ rqq = RubyQmail::Queue.new
32
+ sucess? = rqq.qmail_queue "bounces-123@example.com", ['recipient@email.com',...], message_file
33
+ puts rqq.response #=> Response message
34
+
35
+ You can also specify a set of options on the invocation line as :name=>value parameters after the message file.
36
+ RubyQmail::Queue.insert "bounces-123@example.com", recipient_file, message_file, :method=>:qmqp
37
+ Options can be
38
+ * :config_file - Location of the YAML file with these config settings for the application/system.
39
+ * :qmail_root - Location of the qmail install, usually /var/qmail
40
+ * :qmqp_port - Where any QMQP daemon process is listening, usually 628
41
+ * :logger - Object used to log any messages, such as RAILS_DEFAULT_LOGGER
42
+ * :qmail_queue - The name of the qmail-queue binary (qmail-queue or qmail-qmqpc or other).
43
+ * :qmqp_servers - The location of the time used to specify the IP address of a QMQPD process
44
+ * :ip - The IP address of a QMQP server
45
+ * :method - either :qmqp or :queue, used on the #insert method
46
+ * :noverp - Do not use VERP encoding on the return path
47
+ * :delimiter - Character to separate the email address and VERP encoding (Qmail prefers '-', others user '+')
48
+
49
+ == Feature Path
50
+ * Queue management, moving, reporting
51
+ * Bounce handling
52
+
53
+ == Note on Patches/Pull Requests
54
+
55
+ * Fork the project.
56
+ * Make your feature addition or bug fix.
57
+ * Add tests for it. This is important so I don't break it in a
58
+ future version unintentionally.
59
+ * Commit, do not mess with rakefile, version, or history.
60
+ (if you want to have your own version, that is fine but
61
+ bump version in a commit by itself I can ignore when I pull)
62
+ * Send me a pull request. Bonus points for topic branches.
63
+
64
+ == Copyright
65
+
66
+ Copyright (c) 2009 Allen Fair. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ruby-qmail"
8
+ gem.summary = %Q{Ruby interfaces for Qmail}
9
+ gem.description = %Q{Provides methods to interact with Qmail to send/queue messages, manage bounces, and manage the queue.}
10
+ gem.email = "allen.fair@gmail.com"
11
+ gem.homepage = "http://github.com/afair/ruby-qmail"
12
+ gem.authors = ["Allen Fair"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "ruby-qmail #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/bounce.rb ADDED
@@ -0,0 +1,44 @@
1
+ module RubyQmail
2
+ # Bounce Handler for Qmail Bounce messages. There are typically two types of bounces
3
+ # * Remote Bounces - When email is accepted by the remote email server, then it cannot be delivered, it
4
+ # sends the message with its own error message to the Return-Path or sender address (not necessarily the
5
+ # same one in the From: header--although some non-RFC-compliant servers still will do this). For this
6
+ # processing, it is useful to enable VERP (RubyQmail does this). VERP (Variable Envelope Return Path) in
7
+ # Qmail appends the recipient's email address to each unique delivery, replacing the @ by the = symbol
8
+ # (returnpath-recipient=recipdomain@example.com).
9
+ # * Undeliverable Bounces - An email is sent back to the reuturn path with a formatted report off all undeliverable
10
+ # addresses (where the remote server could not be reached or accept delivery) and the error message
11
+ # generated by Qmail or returned by the Remote server during the SMTP session.
12
+ class BounceHandler
13
+
14
+
15
+ def initialize(bounce_io)
16
+ @bounce_io = bounce_io
17
+ end
18
+
19
+ # Parses a Qmail bounce message as IO object, then calls block with |address, message| for each bounced address
20
+ def parse(&block)
21
+ address=nil
22
+ mesage=nil
23
+ bounces=0
24
+ @bounce_io.each do |line|
25
+ break if line =~ /^--- Below this line is a copy of the message\./
26
+ if line =~ /^<(\S+)>:/
27
+ address = $1
28
+ message=''
29
+ bounces += 1
30
+ elsif bounces==0
31
+ next
32
+ #elsif line ~! /\S/ # empty
33
+ # yield address, message
34
+ elsif line =~ /Remote host said: (.+)/
35
+ yield address, $1
36
+ #message += line
37
+ end
38
+ end
39
+ bounces
40
+ end
41
+
42
+ end
43
+
44
+ end
data/lib/config.rb ADDED
@@ -0,0 +1,31 @@
1
+ module RubyQmail
2
+ require 'logger'
3
+
4
+ # Configuration for the Qmail system. Loads a configuration YAML file, and accepts a Hash of run-time overrides.
5
+ class Config
6
+ attr_reader :options
7
+ DEFAULTS = {
8
+ :qmqp_port => 628,
9
+ :qmail_root => '/var/qmail',
10
+ :delimiter => '-',
11
+ :logger => Logger.new("#{ENV['HOME']}/logs/ruby-qmail.log")
12
+ }
13
+ QMQP_SERVERS = '/control/qmqpservers'
14
+ QMAIL_QUEUE = '/bin/qmail-queue'
15
+
16
+ def self.load_file(config_file, options={})
17
+ @options = DEFAULTS.merge(options)
18
+ if config_file && File.exists?(config_file)
19
+ @options = YAML.load_file(config_file).merge(@options)
20
+ end
21
+ @options[:qmail_queue] ||= @options[:qmail_root] + QMAIL_QUEUE
22
+ @options[:qmqp_servers] ||= @options[:qmail_root] + QMQP_SERVERS
23
+ @options
24
+ end
25
+
26
+ def method_missing(method)
27
+ @options[method.to_sym]
28
+ end
29
+
30
+ end
31
+ end
data/lib/netstring.rb ADDED
@@ -0,0 +1,13 @@
1
+ module RubyQmail
2
+ module Netstring
3
+
4
+ # Converts the string to a netstring: "length:value,"
5
+ def to_netstring()
6
+ "#{self.size}:#{self},"
7
+ end
8
+ end
9
+ end
10
+
11
+ class String#:nodoc:
12
+ include RubyQmail::Netstring
13
+ end
data/lib/queue.rb ADDED
@@ -0,0 +1,248 @@
1
+ module RubyQmail
2
+
3
+ class Queue
4
+ include Process
5
+ attr_accessor( :return_path, :message, :recipients, :options, :response, :success )
6
+ QMAIL_QUEUE_SUCCESS = 0
7
+ QMAIL_ERRORS = {
8
+ -1 => "Unknown Error",
9
+ 0 => "Success",
10
+ 11 => "Address too long",
11
+ 31 => "Mail server permanently refuses to send the message to any recipients.",
12
+ 51 => "Out of memory.",
13
+ 52 => "Timeout.",
14
+ 53 => "Write error; e.g., disk full.",
15
+ 54 => "Unable to read the message or envelope.",
16
+ 55 => "Unable to read a configuration file.",
17
+ 56 => "Problem making a network connection from this host.",
18
+ 61 => "Problem with the qmail home directory.",
19
+ 62 => "Problem with the queue directory.",
20
+ 63 => "Problem with queue/pid.",
21
+ 64 => "Problem with queue/mess.",
22
+ 65 => "Problem with queue/intd.",
23
+ 66 => "Problem with queue/todo.",
24
+ 71 => "Mail server temporarily refuses to send the message to any recipients.",
25
+ 72 => "Connection to mail server timed out.",
26
+ 73 => "Connection to mail server rejected. ",
27
+ 74 => "Connection to mail server succeeded, but communication failed.",
28
+ 81 => "Internal bug; e.g., segmentation fault.",
29
+ 91 => "Envelope format error"
30
+ }
31
+
32
+ # Class Method to place the message into the Qmail queue.
33
+ def self.insert(return_path, recipients, message, *options)
34
+ q = Queue.new(return_path, recipients, message, *options)
35
+ if q.options.has_key?[:ip] || q.options[:method]==:qmqp
36
+ q.qmqp
37
+ else
38
+ q.qmail_queue
39
+ end
40
+ end
41
+
42
+ # Recipients can be a filename, array or other object that responds to :each, or #to_s resolves to an email address
43
+ # Message can be a filename, string, or other object that responds to :each
44
+ def initialize(return_path=nil, recipients=nil, message=nil, *options)
45
+ parameters(return_path, recipients, message, options)
46
+ end
47
+
48
+ def parameters(return_path, recipients, message, options) #:nodoc:
49
+ @return_path = return_path if return_path
50
+ @options = RubyQmail::Config.load_file( nil, options.last || {})
51
+ @recipients = recipients if recipients
52
+ @recipients = File.new(@recipients) if @recipients.is_a?(String) && File.exists?(@recipients)
53
+ @recipients = [ @recipients.to_s ] unless @recipients.respond_to?(:each)
54
+ @message = message if message
55
+ @message = File.new(@message) if @message.is_a?(String) && File.exists?(@message)
56
+ @message = @message.split(/\n/) if @message.is_a?(String)
57
+
58
+ # Edits the return path for VERP. bounces@example.com => bounces-@example.com-@[]
59
+ if return_path && !@options.has_key?(:noverp)
60
+ rp1, rp2 = return_path.split(/@/)
61
+ @return_path = "#{rp1}#{@options[:delimiter]}@#{rp2}" if (rp1.match(/(.)$/)[1] != @options[:delimiter])
62
+ @return_path += '-@[]' unless @return_path =~ /-@\[\]$/
63
+ end
64
+ end
65
+
66
+ # This calls the Qmail-Queue program, so requires qmail to be installed (does not require it to be currently running).
67
+ def queue(return_path=nil, recipients=nil, message=nil, *options)
68
+ parameters(return_path, recipients, message, options)
69
+ @success = run_qmail_queue() do |msg, env|
70
+ # Send the Message
71
+ @message.each { |m| msg.puts(m) }
72
+ msg.close
73
+
74
+ env.write('F' + @return_path + "\0")
75
+ @recipients.each { |r| env.write('T' + r + "\0") }
76
+ env.write("\0") # End of "file"
77
+ end
78
+ @options[:logger].info("RubyQmail Queue exited:#{@success} #{Queue.qmail_queue_error_message(@success)}")
79
+ return true if @success == QMAIL_QUEUE_SUCCESS
80
+ raise Queue.qmail_queue_error_message(@success)
81
+ end
82
+
83
+ # Maps the qmail-queue exit code to the error message
84
+ def self.qmail_queue_error_message(code) #:nodoc:
85
+ "RubyQmail::Queue Error #{code}:" + QMAIL_ERRORS.has_key?(code) ? QMAIL_ERRORS[code]:QMAIL_ERRORS[-1]
86
+ end
87
+
88
+ # Builds the QMQP request, and opens a connection to the QMQP Server and sends
89
+ # This implemtents the QMQP protocol, so does not need Qmail installed on the host system.
90
+ # System defaults will be used if no ip or port given.
91
+ # Returns true on success, false on failure (see @response), or nul on deferral
92
+ def qmqp(return_path=nil, recipients=nil, message=nil, *options)
93
+ parameters(return_path, recipients, message, options)
94
+
95
+ begin
96
+ ip = @options[:ip] || File.readlines(QMQP_SERVERS).first.chomp
97
+ #puts "CONNECT #{:ip}, #{@options[:qmqp_port]}"
98
+ socket = TCPSocket.new(ip, @options[:qmqp_port])
99
+ raise "QMQP can not connect to #{ip}:#{@options[:qmqp_port]}" unless socket
100
+
101
+ # Build netstring of messagebody+returnpath+recipient...
102
+ nstr = (@message.map.join("\n")+"\n").to_netstring # { |m| m }.join("\t").to_netstring
103
+ nstr += @return_path.to_netstring
104
+ nstr += @recipients.map { |r| r.to_netstring }.join
105
+ socket.send( nstr.to_netstring, 0 )
106
+
107
+ @response = socket.recv(1000) # "23:Kok 1182362995 qp 21894," (its a netstring)
108
+ @success = case @response.match(/^\d+:([KZD])(.+),$/)[1]
109
+ when 'K' : true # success
110
+ when 'Z' : nil # deferral
111
+ when 'D' : false # failure
112
+ else false
113
+ end
114
+ logmsg = "RubyQmail QMQP [#{ip}:#{@options[:qmqp_port]}]: #{@response} return:#{@success}"
115
+ @options[:logger].info(logmsg)
116
+ puts logmsg
117
+ @success
118
+ rescue Exception => e
119
+ @options[:logger].error( "QMQP can not connect to #{@opt[:qmqp_ip]}:#{@options[:qmqp_port]} #{e}" )
120
+ raise e
121
+ ensure
122
+ socket.close if socket
123
+ end
124
+ end
125
+
126
+ # # Like #qmail_queue, but writes directly to the queue, not via the qmail-queue program
127
+ # # Is this a good idea? It expects a unique PID per message.
128
+ # def qmail_queue_direct(return_path=nil, recipients=nil, message=nil, *options)
129
+ # parameters(return_path, recipients, message, options)
130
+ # end
131
+
132
+ # def sendmail(return_path=nil, recipients=nil, message=nil, *options)
133
+ # parameters(return_path, recipients, message, options)
134
+ # end
135
+
136
+ # Sends email directly via qmail-remote. It does not store in the queue, It will halt the process
137
+ # and wait for the network event to complete. If multiple recipients are passed, it will run
138
+ # qmail-remote delivery for each at a time to honor VERP return paths.
139
+ def qmail_remote(return_path=nil, recipients=nil, message=nil, *options)
140
+ parameters(return_path, recipients, message, options)
141
+ rp1, rp2 = @return_path.split(/@/,2)
142
+ rp = @return_path
143
+ @recipients.each do |recip|
144
+ unless @options[:noverp]
145
+ mailbox, host = recip.split(/@/)
146
+ rp = "#{rp1}#{mailbox}=#{host}@#{rp2}"
147
+ end
148
+
149
+ @message.rewind if @message.respond_to?(:rewind)
150
+ cmd = "#{@options[:qmail_root]}+/bin/qmail-remote #{host} #{rp} #{recip}"
151
+ @success = self.spawn_command(cmd) do |send, recv|
152
+ @message.each { |m| send.puts m }
153
+ send.close
154
+ @response = recv.readpartial(1000)
155
+ end
156
+
157
+ @options[:logger].info("RubyQmail Remote #{recip} exited:#{@success} responded:#{@response}")
158
+ end
159
+ return [ @success, @response ] # Last one
160
+ end
161
+
162
+ # Forks, sets up stdin and stdout pipes, and starts the command.
163
+ # IF a block is passed, yeilds to it with [sendpipe, receivepipe],
164
+ # returing the exit code, otherwise returns {:send=>, :recieve=>, :pid=>}
165
+ # qmail-queue does not work with this as it reads from both pipes.
166
+ def spawn_command(command, &block)
167
+ child_read, parent_write = IO.pipe # From parent to child(stdin)
168
+ parent_read, child_write = IO.pipe # From child(stdout) to parent
169
+ @child = fork
170
+
171
+ # Child process
172
+ unless @child #
173
+ $stdin.close # closes FD==0
174
+ child_read.dup # copies to FD==0
175
+ child_read.close
176
+
177
+ $stdout.close # closes FD==1
178
+ child_write.dup # copies to FD==1
179
+ child_write.close
180
+
181
+ Dir.chdir(@options[:qmail_root]) unless @options[:nochdir]
182
+ exec(command)
183
+ raise "Exec spawn_command #{command} failed"
184
+ end
185
+
186
+ # Parent Process with block
187
+ if block_given?
188
+ yield(parent_write, parent_read)
189
+ parent_write.close
190
+ parent_read.close
191
+ wait(@child)
192
+ @success = $? >> 8
193
+ return @sucess
194
+ end
195
+
196
+ # Parent process, no block
197
+ {:send=>parent_write, :receive=>parent_read, :pid=>@child}
198
+ end
199
+
200
+ # Forks, sets up stdin and stdout pipes, and starts qmail-queue.
201
+ # IF a block is passed, yields to it with [sendpipe, receivepipe],
202
+ # and returns the exist cod, otherwise returns {:msg=>pipe, :env=>pipe, :pid=>@child}
203
+ # It exits 0 on success or another code on failure.
204
+ # Qmail-queue Protocol: Reads mail message from File Descriptor 0, then reads Envelope from FD 1
205
+ # Envelope Stream: 'F' + sender_email + "\0" + ("T" + recipient_email + "\0") ... + "\0"
206
+ def run_qmail_queue(command=nil, &block)
207
+ # Set up pipes and qmail-queue child process
208
+ msg_read, msg_write = IO.pipe
209
+ env_read, env_write = IO.pipe
210
+ @child=fork # child? nil : childs_process_id
211
+
212
+ unless @child
213
+ ## Set child's stdin(0) to read from msg
214
+ $stdin.close # FD=0
215
+ msg_read.dup
216
+ msg_read.close
217
+ msg_write.close
218
+
219
+ ## Set child's stdout(1) to read from env
220
+ $stdout.close # FD=1
221
+ env_read.dup
222
+ env_read.close
223
+ env_write.close
224
+
225
+ # Change directory and load command
226
+ Dir.chdir(@options[:qmail_root])
227
+ exec( command || @options[:qmail_queue] )
228
+ raise "Exec qmail-queue failed"
229
+ end
230
+
231
+ # Parent Process with block
232
+ if block_given?
233
+ yield(msg_write, env_write)
234
+ # msg_write.close
235
+ env_write.close
236
+ wait(@child)
237
+ @success = $? >> 8
238
+ # puts "#{$$} parent waited for #{@child} s=#{@success} #{$?.inspect}"
239
+ return @sucess
240
+ end
241
+
242
+ # Parent process, no block
243
+ {:msg=>msg_write, :env=>env_write, :pid=>@child}
244
+ end
245
+
246
+ end
247
+
248
+ end
data/lib/ruby-qmail.rb ADDED
@@ -0,0 +1,6 @@
1
+ require File.dirname(__FILE__) + "/netstring"
2
+ require File.dirname(__FILE__) + "/config"
3
+ require File.dirname(__FILE__) + "/queue"
4
+ # require File.dirname(__FILE__) + "/"
5
+ # require File.dirname(__FILE__) + "/"
6
+ # require File.dirname(__FILE__) + "/"
@@ -0,0 +1,33 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'rubygems'
3
+ require 'ruby-debug'
4
+
5
+ describe "RubyQmail" do
6
+
7
+ before(:all) do
8
+ @rqq = RubyQmail::Queue.new()
9
+ @rpath = 'allen-whitelist@biglist.com'
10
+ @recip = %w( allen-1@biglist.com allen-2@biglist.com )
11
+ @msg = %q(To: allen-admin@biglist.com
12
+ From: allen-listmaster@biglist.com
13
+ Subject: ruby-qmail
14
+
15
+ testing 1 2 3.
16
+ later!
17
+ )
18
+ end
19
+
20
+ it "should add a #to_netstring method to the string class" do
21
+ "qmail".to_netstring.should == "5:qmail,"
22
+ end
23
+
24
+ it "should submit a message by qmail-queue" do
25
+ @rqq.queue( @rpath, @recip, @msg ).should_equal true
26
+ end
27
+
28
+ it "should submit a message by QMQP" do
29
+ @rqq.qmqp( @rpath, @recip, @msg, :ip=>'173.161.130.227', :qmqp_port=>631 ).should_equal true
30
+ end
31
+
32
+
33
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'ruby-qmail'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-qmail
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Allen Fair
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-28 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9
24
+ version:
25
+ description: Provides methods to interact with Qmail to send/queue messages, manage bounces, and manage the queue.
26
+ email: allen.fair@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - .document
36
+ - .gitignore
37
+ - LICENSE
38
+ - README.rdoc
39
+ - Rakefile
40
+ - VERSION
41
+ - lib/bounce.rb
42
+ - lib/config.rb
43
+ - lib/netstring.rb
44
+ - lib/queue.rb
45
+ - lib/ruby-qmail.rb
46
+ - spec/ruby-qmail_spec.rb
47
+ - spec/spec.opts
48
+ - spec/spec_helper.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/afair/ruby-qmail
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.5
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Ruby interfaces for Qmail
77
+ test_files:
78
+ - spec/ruby-qmail_spec.rb
79
+ - spec/spec_helper.rb