Class: RubyQmail::Queue
Constant Summary collapse
- QMAIL_QUEUE_SUCCESS =
0
- QMAIL_ERRORS =
{ -1 => "Unknown Error", 0 => "Success", 11 => "Address too long", 31 => "Mail server permanently refuses to send the message to any recipients.", 51 => "Out of memory.", 52 => "Timeout.", 53 => "Write error; e.g., disk full.", 54 => "Unable to read the message or envelope.", 55 => "Unable to read a configuration file.", 56 => "Problem making a network connection from this host.", 61 => "Problem with the qmail home directory.", 62 => "Problem with the queue directory.", 63 => "Problem with queue/pid.", 64 => "Problem with queue/mess.", 65 => "Problem with queue/intd.", 66 => "Problem with queue/todo.", 71 => "Mail server temporarily refuses to send the message to any recipients.", 72 => "Connection to mail server timed out.", 73 => "Connection to mail server rejected. ", 74 => "Connection to mail server succeeded, but communication failed.", 81 => "Internal bug; e.g., segmentation fault.", 91 => "Envelope format error" }
Instance Attribute Summary collapse
-
#message ⇒ Object
Returns the value of attribute message.
-
#options ⇒ Object
Returns the value of attribute options.
-
#recipients ⇒ Object
Returns the value of attribute recipients.
-
#response ⇒ Object
Returns the value of attribute response.
-
#return_path ⇒ Object
Returns the value of attribute return_path.
-
#success ⇒ Object
Returns the value of attribute success.
Class Method Summary collapse
-
.insert(return_path, recipients, message, *options) ⇒ Object
Class Method to place the message into the Qmail queue.
-
.qmail_queue_error_message(code) ⇒ Object
Maps the qmail-queue exit code to the error message.
Instance Method Summary collapse
-
#initialize(return_path = nil, recipients = nil, message = nil, *options) ⇒ Queue
constructor
Recipients can be a filename, array or other object that responds to :each, or #to_s resolves to an email address Message can be a filename, string, or other object that responds to :each.
-
#parameters(return_path, recipients, message, options) ⇒ Object
:nodoc:.
-
#qmail_remote(return_path = nil, recipients = nil, message = nil, *options) ⇒ Object
Sends email directly via qmail-remote.
-
#qmqp(return_path = nil, recipients = nil, message = nil, *options) ⇒ Object
Builds the QMQP request, and opens a connection to the QMQP Server and sends This implemtents the QMQP protocol, so does not need Qmail installed on the host system.
-
#queue(return_path = nil, recipients = nil, message = nil, *options) ⇒ Object
This calls the Qmail-Queue program, so requires qmail to be installed (does not require it to be currently running).
-
#run_qmail_queue(command = nil, &block) ⇒ Object
Forks, sets up stdin and stdout pipes, and starts qmail-queue.
-
#spawn_command(command, &block) ⇒ Object
Forks, sets up stdin and stdout pipes, and starts the command.
Constructor Details
#initialize(return_path = nil, recipients = nil, message = nil, *options) ⇒ Queue
Recipients can be a filename, array or other object that responds to :each, or #to_s resolves to an email address Message can be a filename, string, or other object that responds to :each
44 45 46 |
# File 'lib/queue.rb', line 44 def initialize(return_path=nil, recipients=nil, =nil, *) parameters(return_path, recipients, , ) end |
Instance Attribute Details
#message ⇒ Object
Returns the value of attribute message.
5 6 7 |
# File 'lib/queue.rb', line 5 def @message end |
#options ⇒ Object
Returns the value of attribute options.
5 6 7 |
# File 'lib/queue.rb', line 5 def @options end |
#recipients ⇒ Object
Returns the value of attribute recipients.
5 6 7 |
# File 'lib/queue.rb', line 5 def recipients @recipients end |
#response ⇒ Object
Returns the value of attribute response.
5 6 7 |
# File 'lib/queue.rb', line 5 def response @response end |
#return_path ⇒ Object
Returns the value of attribute return_path.
5 6 7 |
# File 'lib/queue.rb', line 5 def return_path @return_path end |
#success ⇒ Object
Returns the value of attribute success.
5 6 7 |
# File 'lib/queue.rb', line 5 def success @success end |
Class Method Details
.insert(return_path, recipients, message, *options) ⇒ Object
Class Method to place the message into the Qmail queue.
33 34 35 36 37 38 39 40 |
# File 'lib/queue.rb', line 33 def self.insert(return_path, recipients, , *) q = Queue.new(return_path, recipients, , *) if q..has_key?[:ip] || q.[:method]==:qmqp q.qmqp else q.qmail_queue end end |
.qmail_queue_error_message(code) ⇒ Object
Maps the qmail-queue exit code to the error message
84 85 86 |
# File 'lib/queue.rb', line 84 def self.(code) #:nodoc: "RubyQmail::Queue Error #{code}:" + QMAIL_ERRORS.has_key?(code) ? QMAIL_ERRORS[code]:QMAIL_ERRORS[-1] end |
Instance Method Details
#parameters(return_path, recipients, message, options) ⇒ Object
:nodoc:
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/queue.rb', line 48 def parameters(return_path, recipients, , ) #:nodoc: @return_path = return_path if return_path @options = RubyQmail::Config.load_file( nil, .last || {}) @recipients = recipients if recipients @recipients = File.new(@recipients) if @recipients.is_a?(String) && File.exists?(@recipients) @recipients = [ @recipients.to_s ] unless @recipients.respond_to?(:each) @message = if @message = File.new(@message) if @message.is_a?(String) && File.exists?(@message) @message = @message.split(/\n/) if @message.is_a?(String) # Edits the return path for VERP. [email protected] => [email protected]@[] if return_path && !@options.has_key?(:noverp) rp1, rp2 = return_path.split(/@/) @return_path = "#{rp1}#{@options[:delimiter]}@#{rp2}" if (rp1.match(/(.)$/)[1] != @options[:delimiter]) @return_path += '-@[]' unless @return_path =~ /-@\[\]$/ end end |
#qmail_remote(return_path = nil, recipients = nil, message = nil, *options) ⇒ Object
Sends email directly via qmail-remote. It does not store in the queue, It will halt the process and wait for the network event to complete. If multiple recipients are passed, it will run qmail-remote delivery for each at a time to honor VERP return paths.
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/queue.rb', line 139 def qmail_remote(return_path=nil, recipients=nil, =nil, *) parameters(return_path, recipients, , ) rp1, rp2 = @return_path.split(/@/,2) rp = @return_path @recipients.each do |recip| unless @options[:noverp] mailbox, host = recip.split(/@/) rp = "#{rp1}#{mailbox}=#{host}@#{rp2}" end @message.rewind if @message.respond_to?(:rewind) cmd = "#{@options[:qmail_root]}+/bin/qmail-remote #{host} #{rp} #{recip}" @success = self.spawn_command(cmd) do |send, recv| @message.each { |m| send.puts m } send.close @response = recv.readpartial(1000) end @options[:logger].info("RubyQmail Remote #{recip} exited:#{@success} responded:#{@response}") end return [ @success, @response ] # Last one end |
#qmqp(return_path = nil, recipients = nil, message = nil, *options) ⇒ Object
Builds the QMQP request, and opens a connection to the QMQP Server and sends This implemtents the QMQP protocol, so does not need Qmail installed on the host system. System defaults will be used if no ip or port given. Returns true on success, false on failure (see @response), or nul on deferral
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/queue.rb', line 92 def qmqp(return_path=nil, recipients=nil, =nil, *) parameters(return_path, recipients, , ) begin ip = @options[:ip] || File.readlines(QMQP_SERVERS).first.chomp #puts "CONNECT #{:ip}, #{@options[:qmqp_port]}" socket = TCPSocket.new(ip, @options[:qmqp_port]) raise "QMQP can not connect to #{ip}:#{@options[:qmqp_port]}" unless socket # Build netstring of messagebody+returnpath+recipient... nstr = (@message.map.join("\n")+"\n").to_netstring # { |m| m }.join("\t").to_netstring nstr += @return_path.to_netstring nstr += @recipients.map { |r| r.to_netstring }.join socket.send( nstr.to_netstring, 0 ) @response = socket.recv(1000) # "23:Kok 1182362995 qp 21894," (its a netstring) @success = case @response.match(/^\d+:([KZD])(.+),$/)[1] when 'K' then true # success when 'Z' then nil # deferral when 'D' then false # failure else false end logmsg = "RubyQmail QMQP [#{ip}:#{@options[:qmqp_port]}]: #{@response} return:#{@success}" @options[:logger].info(logmsg) puts logmsg @success rescue Exception => e @options[:logger].error( "QMQP can not connect to #{@opt[:qmqp_ip]}:#{@options[:qmqp_port]} #{e}" ) raise e ensure socket.close if socket end end |
#queue(return_path = nil, recipients = nil, message = nil, *options) ⇒ Object
This calls the Qmail-Queue program, so requires qmail to be installed (does not require it to be currently running).
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/queue.rb', line 67 def queue(return_path=nil, recipients=nil, =nil, *) parameters(return_path, recipients, , ) @success = run_qmail_queue() do |msg, env| # Send the Message @message.each { |m| msg.puts(m) } msg.close env.write('F' + @return_path + "\0") @recipients.each { |r| env.write('T' + r + "\0") } env.write("\0") # End of "file" end @options[:logger].info("RubyQmail Queue exited:#{@success} #{Queue.(@success)}") return true if @success == QMAIL_QUEUE_SUCCESS raise Queue.(@success) end |
#run_qmail_queue(command = nil, &block) ⇒ Object
Forks, sets up stdin and stdout pipes, and starts qmail-queue. IF a block is passed, yields to it with [sendpipe, receivepipe], and returns the exist cod, otherwise returns :env=>pipe, :pid=>@child It exits 0 on success or another code on failure. Qmail-queue Protocol: Reads mail message from File Descriptor 0, then reads Envelope from FD 1 Envelope Stream: ‘F’ + sender_email + “0” + (“T” + recipient_email + “0”) … + “0”
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/queue.rb', line 206 def run_qmail_queue(command=nil, &block) # Set up pipes and qmail-queue child process msg_read, msg_write = IO.pipe env_read, env_write = IO.pipe @child=fork # child? nil : childs_process_id unless @child ## Set child's stdin(0) to read from msg $stdin.close # FD=0 msg_read.dup msg_read.close msg_write.close ## Set child's stdout(1) to read from env $stdout.close # FD=1 env_read.dup env_read.close env_write.close # Change directory and load command Dir.chdir(@options[:qmail_root]) exec( command || @options[:qmail_queue] ) raise "Exec qmail-queue failed" end # Parent Process with block if block_given? yield(msg_write, env_write) # msg_write.close env_write.close wait(@child) @success = $? >> 8 # puts "#{$$} parent waited for #{@child} s=#{@success} #{$?.inspect}" return @sucess end # Parent process, no block {:msg=>msg_write, :env=>env_write, :pid=>@child} end |
#spawn_command(command, &block) ⇒ Object
Forks, sets up stdin and stdout pipes, and starts the command. IF a block is passed, yeilds to it with [sendpipe, receivepipe], returing the exit code, otherwise returns :recieve=>, :pid=> qmail-queue does not work with this as it reads from both pipes.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/queue.rb', line 166 def spawn_command(command, &block) child_read, parent_write = IO.pipe # From parent to child(stdin) parent_read, child_write = IO.pipe # From child(stdout) to parent @child = fork # Child process unless @child # $stdin.close # closes FD==0 child_read.dup # copies to FD==0 child_read.close $stdout.close # closes FD==1 child_write.dup # copies to FD==1 child_write.close Dir.chdir(@options[:qmail_root]) unless @options[:nochdir] exec(command) raise "Exec spawn_command #{command} failed" end # Parent Process with block if block_given? yield(parent_write, parent_read) parent_write.close parent_read.close wait(@child) @success = $? >> 8 return @sucess end # Parent process, no block {:send=>parent_write, :receive=>parent_read, :pid=>@child} end |