diff --git a/ChangeLog b/ChangeLog index 2ffca19484..61dde9cfa9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Wed Jul 2 11:45:34 2003 Minero Aoki + + * lib/net/smtp.rb: synchronize document with source code. + + * lib/net/pop.rb: ditto. + Wed Jul 2 11:39:50 2003 Minero Aoki * lib/net/smtp.rb: unify SMTP and SMTPCommand. diff --git a/lib/net/pop.rb b/lib/net/pop.rb index 67542d794e..09d172df06 100644 --- a/lib/net/pop.rb +++ b/lib/net/pop.rb @@ -18,7 +18,7 @@ $Id$ == What is This Module? -This module provides your program the functions to retrieve +This module provides your program the function to retrieve mails via POP3, Post Office Protocol version 3. For details of POP3, refer [RFC1939] (()). @@ -32,22 +32,22 @@ Replace 'pop3.server.address' your POP3 server address. require 'net/pop' - pop = Net::POP3.new('pop3.server.address', 110) - pop.start('YourAccount', 'YourPassword') ### - if pop.mails.empty? then + pop = Net::POP3.new('pop.example.com', 110) + pop.start('YourAccount', 'YourPassword') # (1) + if pop.mails.empty? puts 'no mail.' else i = 0 - pop.each_mail do |m| # or "pop.mails.each ..." - File.open('inbox/' + i.to_s, 'w') {|f| - f.write m.pop + pop.each_mail do |m| # or "pop.mails.each ..." # (2) + File.open("inbox/#{i}", 'w') {|f| + f.write m.pop } m.delete i += 1 end puts "#{pop.mails.size} mails popped." end - pop.finish ### + pop.finish # (3) (1) call Net::POP3#start and start POP session (2) access mails by using POP3#each_mail and/or POP3#mails @@ -63,40 +63,40 @@ alternates POP3.new, POP3#start and POP3#finish. require 'net/pop' - Net::POP3.start('pop3.server.address', 110) - 'YourAccount', 'YourPassword') - if pop.mails.empty? - puts 'no mail.' - else - i = 0 - pop.each_mail do |m| # or "pop.mails.each ..." - File.open('inbox/' + i.to_s, 'w') {|f| - f.write m.pop - } - m.delete - i += 1 - end - puts "#{pop.mails.size} mails popped." + Net::POP3.start('pop.example.com', 110, + 'YourAccount', 'YourPassword') {|pop| + if pop.mails.empty? + puts 'no mail.' + else + i = 0 + pop.each_mail do |m| # or "pop.mails.each ..." + File.open("inbox/#{i}", 'w') {|f| + f.write m.pop + } + m.delete + i += 1 end + puts "#{pop.mails.size} mails popped." + end } POP3#delete_all alternates #each_mail and m.delete. require 'net/pop' - Net::POP3.start('pop3.server.address', 110, + Net::POP3.start('pop.example.com', 110, 'YourAccount', 'YourPassword') {|pop| - if pop.mails.empty? - puts 'no mail.' - else - i = 0 - pop.delete_all do |m| - File.open('inbox/' + i.to_s, 'w') {|f| - f.write m.pop - } - i += 1 - end + if pop.mails.empty? + puts 'no mail.' + else + i = 1 + pop.delete_all do |m| + File.open("inbox/#{i}", 'w') {|f| + f.write m.pop + } + i += 1 end + end } And here is more shorter example. @@ -104,24 +104,29 @@ And here is more shorter example. require 'net/pop' i = 0 - Net::POP3.delete_all('pop3.server.address', 110, + Net::POP3.delete_all('pop.example.com', 110, 'YourAccount', 'YourPassword') do |m| - File.open('inbox/' + i.to_s, 'w') {|f| - f.write m.pop + File.open("inbox/#{i}", 'w') {|f| + f.write m.pop } i += 1 end -=== Writing to File directly +=== Memory Space Issue All examples above get mail as one big string. This example does not create such one. require 'net/pop' - Net::POP3.delete_all('pop3.server.address', 110, + + i = 1 + Net::POP3.delete_all('pop.example.com', 110, 'YourAccount', 'YourPassword') do |m| - File.open('inbox', 'w') {|f| - m.pop f #### + File.open("inbox/#{i}", 'w') {|f| + m.pop do |chunk| # get a message little by little. + f.write chunk + end + i += 1 } end @@ -134,12 +139,12 @@ You can use utility method, Net::POP3.APOP(). Example: require 'net/pop' # Use APOP authentication if $isapop == true - pop = Net::POP3.APOP($isapop).new('apop.server.address', 110) + pop = Net::POP3.APOP($is_apop).new('apop.example.com', 110) pop.start(YourAccount', 'YourPassword') {|pop| - # Rest code is same. + # Rest code is same. } -=== Fetch Only Selected Mail Using POP UIDL Function +=== Fetch Only Selected Mail Using `UIDL' POP Command If your POP server provides UIDL function, you can pop only selected mails from POP server. @@ -149,7 +154,7 @@ e.g. # determine if we need pop this mail... end - Net::POP3.start('pop.server', 110, + Net::POP3.start('pop.example.com', 110, 'Your account', 'Your password') {|pop| pop.mails.select {|m| need_pop?(m.unique_id) }.each do |m| do_something(m.pop) @@ -175,53 +180,53 @@ Normally unique-id is a hash of the message. # Typical usage Net::POP3.start(addr, port, account, password) {|pop| - pop.each_mail do |m| - file.write m.pop - m.delete - end + pop.each_mail do |m| + file.write m.pop + m.delete + end } : APOP( is_apop ) - returns Net::APOP class object if IS_APOP is true. - returns Net::POP3 class object if false. - Use this method like: + returns Net::APOP class object if IS_APOP. + Else, IS_APOP. Use this method like: # Example 1 - pop = Net::POP3::APOP($isapop).new( addr, port ) + pop = Net::POP3::APOP($is_apop).new(addr, port) # Example 2 - Net::POP3::APOP($isapop).start( addr, port ) {|pop| - .... + Net::POP3::APOP($is_apop).start(addr, port) {|pop| + .... } -: foreach( address, port = 110, account, password, isapop = false ) {|mail| .... } +: foreach( address, port = 110, account, password, isapop = false ) {|popmail| .... } starts POP3 protocol and iterates for each POPMail object. This method equals to: - Net::POP3.start( address, port, account, password ) {|pop| - pop.each_mail do |m| - yield m - end + Net::POP3.start(address, port, account, password) {|pop| + pop.each_mail do |m| + yield m + end } This method raises POPAuthenticationError if authentication is failed. # Typical usage - Net::POP3.foreach( 'your.pop.server', 110, - 'YourAccount', 'YourPassword' ) do |m| + Net::POP3.foreach('pop.example.com', 110, + 'YourAccount', 'YourPassword') do |m| file.write m.pop m.delete if $DELETE end : delete_all( address, port = 110, account, password, isapop = false ) -: delete_all( address, port = 110, account, password, isapop = false ) {|mail| .... } +: delete_all( address, port = 110, account, password, isapop = false ) {|popmail| .... } starts POP3 session and delete all mails. If block is given, iterates for each POPMail object before delete. This method raises POPAuthenticationError if authentication is failed. # Example - Net::POP3.delete_all( addr, nil, 'YourAccount', 'YourPassword' ) do |m| - m.pop file + Net::POP3.delete_all('pop.example.com', 110, + 'YourAccount', 'YourPassword') do |m| + file.write m.pop end : auth_only( address, port = 110, account, password, isapop = false ) @@ -231,11 +236,13 @@ Normally unique-id is a hash of the message. This method must not be called while POP3 session is opened. This method raises POPAuthenticationError if authentication is failed. - # Example - Net::POP3.auth_only( 'your.pop3.server', - nil, # using default (110) - 'YourAccount', - 'YourPassword' ) + # Example 1: normal POP3 + Net::POP3.auth_only('pop.example.com', 110, + 'YourAccount', 'YourPassword') + + # Example 2: APOP + Net::POP3.auth_only('pop.example.com', 110, + 'YourAccount', 'YourPassword', true) === Instance Methods @@ -249,6 +256,7 @@ Normally unique-id is a hash of the message. This method raises POPAuthenticationError if authentication is failed. : started? +: active? OBSOLETE true if POP3 session is started. : address @@ -283,13 +291,17 @@ Normally unique-id is a hash of the message. an array of Net::POPMail objects. This array is renewed when session restarts. - This method raises POPError if any problem happend. + This method raises POPError if any problem happened. : each_mail {|popmail| .... } : each {|popmail| .... } - is equals to "pop3.mails.each" + is equals to: + + pop3.mails.each do |popmail| + .... + end - This method raises POPError if any problem happend. + This method raises POPError if any problem happened. : delete_all : delete_all {|popmail| .... } @@ -299,16 +311,31 @@ Normally unique-id is a hash of the message. # Example n = 1 pop.delete_all do |m| - File.open("inbox/#{n}") {|f| f.write m.pop } + File.open("inbox/#{n}") {|f| + f.write m.pop + } n += 1 end - This method raises POPError if any problem happend. + This method raises POPError if any problem happened. : reset reset the session. All "deleted mark" are removed. - This method raises POPError if any problem happend. + This method raises POPError if any problem happened. + +: set_debug_output( output ) + WARNING: This method causes serious security hole. + Use this method for only debugging. + + set output stream for debugging. + + # Example + pop = Net::POP.new(addr, port) + pop.set_debug_output $stderr + pop.start(account, passwd) { + .... + } == class Net::APOP @@ -327,58 +354,101 @@ A class of mail which exists on POP server. === Instance Methods -: pop( dest = '' ) - This method fetches a mail and write to 'dest' using '<<' method. +: pop + This method fetches a message as a String. - This method raises POPError if any problem happend. + This method may raise POPError. - # Typical usage - allmails = nil - POP3.start( 'your.pop3.server', 110, - 'YourAccount, 'YourPassword' ) {|pop| - allmails = pop.mails.collect {|popmail| popmail.pop } + # Example + POP3.start('pop.example.com', 110, + 'YourAccount, 'YourPassword') {|pop| + n = 1 + pop.mails.each do |popmail| + File.open("inbox/#{n}", 'w') {|f| + f.write popmail.pop #### + } + popmail.delete + n += 1 + end } -: pop {|str| .... } - gives the block part strings of a mail. +: pop {|chunk| .... } + gives the block parts of the message. - This method raises POPError if any problem happend. + This method may raise POPError. - # Typical usage - POP3.start( 'localhost', 110 ) {|pop3| - pop3.each_mail do |m| - m.pop do |str| - # do anything + # Example + POP3.start('pop.example.com', 110, + 'YourAccount, 'YourPassword') {|pop| + n = 1 + pop.mails.each do |popmail| + File.open("inbox/#{n}", 'w') {|f| + popmail.pop do |chunk| #### + f.write chunk end - end + } + n += 1 + end } : header - fetches only mail header. + fetches the message header. - This method raises POPError if any problem happend. + This method may raise POPError. : top( lines ) - fetches mail header and LINES lines of body. + fetches the message header and LINES lines of body. - This method raises POPError if any problem happend. + This method may raise POPError. : delete - deletes mail on server. + deletes the message on the POP server. - This method raises POPError if any problem happend. + This method may raise POPError. + # Example + POP3.start('pop.example.com', 110, + 'YourAccount, 'YourPassword') {|pop| + n = 1 + pop.mails.each do |popmail| + File.open("inbox/#{n}", 'w') {|f| + f.write popmail.pop + } + popmail.delete #### + n += 1 + end + } + +: length : size - mail size (bytes) + the length of the message (in octets). : deleted? - true if mail was deleted + true if mail was deleted. : unique_id - returns an unique-id of the message. - Normally unique-id is a hash of the message. + returns the unique-id of the message. + Normally unique-id is a hash string of the message. - This method raises POPError if any problem happend. + This method may raise POPError. + + +== POP3 Related Exception Classes + +: POPError + POP3 protocol error (reply code "-ERR", except authentication). + + ancestors: ProtocolError (obsolete) + +: POPAuthenticationError + POP3 authentication error. + + ancestors: POPError, ProtoAuthError (obsolete), ProtocolError (obsolete) + +: POPBadResponse + Unexpected response got from server. + + ancestors: POPError =end diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb index 6329d0731d..240b41d6c7 100644 --- a/lib/net/smtp.rb +++ b/lib/net/smtp.rb @@ -34,9 +34,9 @@ FYI: official documentation of internet mail is: == Examples -=== Sending Mail +=== Sending Message -You must open connection to SMTP server before sending mails. +You must open connection to SMTP server before sending messages. First argument is the address of SMTP server, and second argument is port number. Using SMTP.start with block is the most simple way to do it. SMTP connection is closed automatically after block is @@ -44,61 +44,51 @@ executed. require 'net/smtp' Net::SMTP.start('your.smtp.server', 25) {|smtp| - # use SMTP object only in this block + # use a SMTP object only in this block } Replace 'your.smtp.server' by your SMTP server. Normally your system manager or internet provider is supplying a server for you. -Then you can send mail. +Then you can send messages. - mail_text = < - To: Dest Address - Subject: test mail + To: Destination Address + Subject: test message Date: Sat, 23 Jun 2001 16:26:43 +0900 - Message-Id: + Message-Id: - This is test mail. - END_OF_MAIL + This is a test message. + END_OF_MESSAGE require 'net/smtp' Net::SMTP.start('your.smtp.server', 25) {|smtp| - smtp.send_mail mail_text, - 'your@mail.address', - 'his_addess@example.com' + smtp.send_message msgstr, + 'your@mail.address', + 'his_addess@example.com' } === Closing Session -You MUST close SMTP session after sending mails, by calling #finish -method. You can also use block form of SMTP.start/SMTP#start, which -closes session automatically. I strongly recommend later one. It is -more beautiful and simple. +You MUST close SMTP session after sending messages, by calling #finish +method: # using SMTP#finish smtp = Net::SMTP.start('your.smtp.server', 25) - smtp.send_mail mail_string, 'from@address', 'to@address' + smtp.send_message msgstr, 'from@address', 'to@address' smtp.finish +You can also use block form of SMTP.start/SMTP#start. They closes +SMTP session automatically: + # using block form of SMTP.start Net::SMTP.start('your.smtp.server', 25) {|smtp| - smtp.send_mail mail_string, 'from@address', 'to@address' + smtp.send_message msgstr, 'from@address', 'to@address' } -=== Sending Mails From non-String Sources - -In an example above I has sent mail from String (here document literal). -SMTP#send_mail accepts any objects which has "each" method -like File and Array. - - require 'net/smtp' - Net::SMTP.start('your.smtp.server', 25) {|smtp| - File.open('Mail/draft/1') {|f| - smtp.send_mail f, 'your@mail.address', 'to@some.domain' - } - } +I strongly recommend this scheme. This form is more simple and robust. === HELO domain @@ -113,8 +103,10 @@ the SMTP session by inspecting HELO domain. === SMTP Authentication -net/smtp supports three authentication scheme. +The Net::SMTP class supports three authentication schemes; PLAIN, LOGIN and CRAM MD5. (SMTP Authentication: [RFC2554]) +To use SMTP authentication, pass extra arguments to +SMTP.start/SMTP#start methods. # PLAIN Net::SMTP.start('your.smtp.server', 25, 'mail.from,domain', @@ -127,24 +119,34 @@ PLAIN, LOGIN and CRAM MD5. (SMTP Authentication: [RFC2554]) Net::SMTP.start('your.smtp.server', 25, 'mail.from,domain', 'Your Account', 'Your Password', :cram_md5) - == class Net::SMTP === Class Methods : new( address, port = 25 ) creates a new Net::SMTP object. + This method does not open TCP connection. : start( address, port = 25, helo_domain = 'localhost.localdomain', account = nil, password = nil, authtype = nil ) : start( address, port = 25, helo_domain = 'localhost.localdomain', account = nil, password = nil, authtype = nil ) {|smtp| .... } - is equal to + is equal to: Net::SMTP.new(address,port).start(helo_domain,account,password,authtype) # example - Net::SMTP.start( 'your.smtp.server' ) { - smtp.send_mail mail_string, 'from@mail.address', 'dest@mail.address' + Net::SMTP.start('your.smtp.server') { + smtp.send_message msgstr, 'from@example.com', ['dest@example.com'] } + This method may raise: + + * Net::SMTPAuthenticationError + * Net::SMTPServerBusy + * Net::SMTPSyntaxError + * Net::SMTPFatalError + * Net::SMTPUnknownError + * IOError + * TimeoutError + === Instance Methods : start( helo_domain = , account = nil, password = nil, authtype = nil ) @@ -160,7 +162,18 @@ PLAIN, LOGIN and CRAM MD5. (SMTP Authentication: [RFC2554]) authentication by using AUTH command. AUTHTYPE is an either of :login, :plain, and :cram_md5. + This method may raise: + + * Net::SMTPAuthenticationError + * Net::SMTPServerBusy + * Net::SMTPSyntaxError + * Net::SMTPFatalError + * Net::SMTPUnknownError + * IOError + * TimeoutError + : started? +: active? OBSOLETE true if SMTP session is started. : esmtp? @@ -183,63 +196,128 @@ PLAIN, LOGIN and CRAM MD5. (SMTP Authentication: [RFC2554]) : read_timeout : read_timeout=(n) - seconds to wait until reading one block (by one read(1) call). + seconds to wait until reading one block (by one read(2) call). If SMTP object cannot open a conection in this seconds, it raises TimeoutError exception. : finish finishes SMTP session. If SMTP session had not started, raises an IOError. + If SMTP session timed out, raises TimeoutError. -: send_mail( mailsrc, from_addr, *to_addrs ) - This method sends MAILSRC as mail. A SMTP object read strings - from MAILSRC by calling "each" iterator, with converting them - into CRLF ("\r\n") terminated string when write. +: send_message( msgstr, from_addr, *dest_addrs ) +: send_mail( msgstr, from_addr, *dest_addrs ) +: sendmail( msgstr, from_addr, *dest_addrs ) OBSOLETE + sends a String MSGSTR. If a single CR ("\r") or LF ("\n") found + in the MEGSTR, converts it to the CR LF pair. You cannot send a + binary message with this class. FROM_ADDR must be a String, representing source mail address. TO_ADDRS must be Strings or an Array of Strings, representing destination mail addresses. # example - Net::SMTP.start( 'your.smtp.server' ) {|smtp| - smtp.send_mail mail_string, - 'from@mail.address', - 'dest@mail.address' 'dest2@mail.address' + Net::SMTP.start('smtp.example.com') {|smtp| + smtp.send_message msgstr, + 'from@example.com', + ['dest@example.com', 'dest2@example.com'] } -: ready( from_addr, *to_addrs ) {|adapter| .... } - This method stands by the SMTP object for sending mail and - gives adapter object to the block. ADAPTER has these 5 methods: + This method may raise: - puts print printf write << + * Net::SMTPServerBusy + * Net::SMTPSyntaxError + * Net::SMTPFatalError + * Net::SMTPUnknownError + * IOError + * TimeoutError + +: open_message_stream( from_addr, *dest_addrs ) {|stream| .... } +: ready( from_addr, *dest_addrs ) {|stream| .... } OBSOLETE + opens a message writer stream and gives it to the block. + STREAM is valid only in the block, and has these methods: + + : puts(str = '') + outputs STR and CR LF. + : print(str) + outputs STR. + : printf(fmt, *args) + outputs sprintf(fmt,*args). + : write(str) + outputs STR and returns the length of written bytes. + : <<(str) + outputs STR and returns self. + + If a single CR ("\r") or LF ("\n") found in the message, + converts it to the CR LF pair. You cannot send a binary + message with this class. FROM_ADDR must be a String, representing source mail address. TO_ADDRS must be Strings or an Array of Strings, representing destination mail addresses. # example - Net::SMTP.start( 'your.smtp.server', 25 ) {|smtp| - smtp.ready( 'from@mail.addr', 'dest@mail.addr' ) {|f| - f.puts 'From: aamine@loveruby.net' - f.puts 'To: someone@somedomain.org' - f.puts 'Subject: test mail' - f.puts - f.puts 'This is test mail.' - } + Net::SMTP.start('smtp.example.com', 25) {|smtp| + smtp.open_message_stream('from@example.com', ['dest@example.com']) {|f| + f.puts 'From: from@example.com' + f.puts 'To: dest@example.com' + f.puts 'Subject: test message' + f.puts + f.puts 'This is a test message.' + } } -== Exceptions + This method may raise: -SMTP objects raise these exceptions: + * Net::SMTPServerBusy + * Net::SMTPSyntaxError + * Net::SMTPFatalError + * Net::SMTPUnknownError + * IOError + * TimeoutError -: Net::ProtoSyntaxError - Syntax error (errno.500) -: Net::ProtoFatalError - Fatal error (errno.550) -: Net::ProtoUnknownError - Unknown error. (is probably bug) -: Net::ProtoServerBusy - Temporal error (errno.420/450) +: set_debug_output( output ) + WARNING: This method causes serious security holes. + Use this method for only debugging. + + set an output stream for debug logging. + You must call this before #start. + + # example + smtp = Net::SMTP.new(addr, port) + smtp.set_debug_output $stderr + smtp.start { + .... + } + + +== SMTP Related Exception Classes + +: Net::SMTPAuthenticationError + SMTP authentication error. + + ancestors: SMTPError, ProtoAuthError (obsolete), ProtocolError (obsolete) + +: Net::SMTPServerBusy + Temporal error; error number 420/450. + + ancestors: SMTPError, ProtoServerError (obsolete), ProtocolError (obsolete) + +: Net::SMTPSyntaxError + SMTP command syntax error (error number 500) + + ancestors: SMTPError, ProtoSyntaxError (obsolete), ProtocolError (obsolete) + +: Net::SMTPFatalError + Fatal error (error number 5xx, except 500) + + ancestors: SMTPError, ProtoFatalError (obsolete), ProtocolError (obsolete) + +: Net::SMTPUnknownError + Unexpected reply code returned from server + (might be a bug of this library). + + ancestors: SMTPError, ProtoUnkownError (obsolete), ProtocolError (obsolete) =end