1999-10-13 03:29:15 -04:00
|
|
|
=begin
|
|
|
|
|
1999-12-17 10:00:13 -05:00
|
|
|
= net/smtp.rb
|
1999-10-13 03:29:15 -04:00
|
|
|
|
1999-12-17 10:00:13 -05:00
|
|
|
written by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
|
1999-10-13 03:29:15 -04:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
This library is distributed under the terms of the Ruby license.
|
|
|
|
You can freely distribute/modify this library.
|
1999-10-13 03:29:15 -04:00
|
|
|
|
|
|
|
=end
|
|
|
|
|
1999-09-22 03:32:33 -04:00
|
|
|
|
2000-02-21 10:25:37 -05:00
|
|
|
require 'net/protocol'
|
1999-09-22 03:32:33 -04:00
|
|
|
|
|
|
|
|
1999-12-17 10:00:13 -05:00
|
|
|
module Net
|
|
|
|
|
|
|
|
|
1999-10-13 03:29:15 -04:00
|
|
|
=begin
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
== Net::SMTP
|
1999-10-13 03:29:15 -04:00
|
|
|
|
|
|
|
=== Super Class
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
Net::Protocol
|
1999-10-13 03:29:15 -04:00
|
|
|
|
|
|
|
=== Class Methods
|
|
|
|
|
|
|
|
: new( address = 'localhost', port = 25 )
|
1999-12-29 06:14:04 -05:00
|
|
|
This method create new SMTP object.
|
1999-10-13 03:29:15 -04:00
|
|
|
|
|
|
|
|
|
|
|
=== Methods
|
|
|
|
|
|
|
|
: start( helo_domain = ENV['HOSTNAME'] )
|
1999-12-29 06:14:04 -05:00
|
|
|
This method opens TCP connection and start SMTP.
|
|
|
|
If protocol had been started, do nothing and return false.
|
1999-10-13 03:29:15 -04:00
|
|
|
|
2000-03-05 05:25:53 -05:00
|
|
|
: sendmail( mailsrc, from_addr, to_addrs )
|
2000-01-05 02:55:36 -05:00
|
|
|
This method sends 'mailsrc' as mail. SMTPSession read strings
|
|
|
|
from 'mailsrc' by calling 'each' iterator, and convert them
|
|
|
|
into "\r\n" terminated string when write.
|
1999-10-13 03:29:15 -04:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
Exceptions which SMTP raises are:
|
|
|
|
* Net::ProtoSyntaxError: syntax error (errno.500)
|
|
|
|
* Net::ProtoFatalError: fatal error (errno.550)
|
|
|
|
* Net::ProtoUnknownError: unknown error
|
|
|
|
* Net::ProtoServerBusy: temporary error (errno.420/450)
|
1999-10-13 03:29:15 -04:00
|
|
|
|
2000-03-05 05:25:53 -05:00
|
|
|
: ready( from_addr, to_addrs ) {|adapter| .... }
|
2000-02-21 10:25:37 -05:00
|
|
|
This method stands by the SMTP object for sending mail.
|
|
|
|
In the block of this iterator, you can call ONLY 'write' method
|
|
|
|
for 'adapter'.
|
|
|
|
|
|
|
|
# usage example
|
|
|
|
|
|
|
|
SMTP.start( 'localhost', 25 ) do |smtp|
|
|
|
|
smtp.ready( from, to ) do |adapter|
|
|
|
|
adapter.write str1
|
|
|
|
adapter.write str2
|
|
|
|
adapter.write str3
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
1999-10-13 03:29:15 -04:00
|
|
|
: finish
|
1999-12-29 06:14:04 -05:00
|
|
|
This method ends SMTP.
|
|
|
|
If protocol had not started, do nothind and return false.
|
1999-10-13 03:29:15 -04:00
|
|
|
|
|
|
|
=end
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
class SMTP < Protocol
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
protocol_param :port, '25'
|
|
|
|
protocol_param :command_type, '::Net::SMTPCommand'
|
1999-12-17 10:00:13 -05:00
|
|
|
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def sendmail( mailsrc, fromaddr, toaddrs )
|
|
|
|
do_ready fromaddr, toaddrs
|
2000-03-31 08:02:40 -05:00
|
|
|
@command.write_mail mailsrc, nil
|
2000-02-21 10:25:37 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def ready( fromaddr, toaddrs, &block )
|
2000-03-26 03:48:15 -05:00
|
|
|
do_ready fromaddr, toaddrs
|
2000-03-31 08:02:40 -05:00
|
|
|
@command.write_mail nil, block
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2000-02-21 10:25:37 -05:00
|
|
|
attr :esmtp
|
|
|
|
|
|
|
|
|
1999-09-22 03:32:33 -04:00
|
|
|
private
|
|
|
|
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def do_ready( fromaddr, toaddrs )
|
|
|
|
@command.mailfrom fromaddr
|
|
|
|
@command.rcpt toaddrs
|
|
|
|
@command.data
|
|
|
|
end
|
|
|
|
|
1999-12-17 10:00:13 -05:00
|
|
|
def do_start( helodom = ENV['HOSTNAME'] )
|
1999-09-22 03:32:33 -04:00
|
|
|
unless helodom then
|
1999-12-17 10:00:13 -05:00
|
|
|
raise ArgumentError, "cannot get hostname"
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
2000-02-21 10:25:37 -05:00
|
|
|
|
|
|
|
@esmtp = false
|
|
|
|
begin
|
|
|
|
@command.ehlo helodom
|
|
|
|
@esmtp = true
|
|
|
|
rescue ProtocolError
|
|
|
|
@command.helo helodom
|
|
|
|
end
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
SMTPSession = SMTP
|
1999-09-22 03:32:33 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SMTPCommand < Command
|
|
|
|
|
1999-12-17 10:00:13 -05:00
|
|
|
def initialize( sock )
|
|
|
|
super
|
2000-03-27 10:52:27 -05:00
|
|
|
critical {
|
|
|
|
check_reply SuccessCode
|
|
|
|
}
|
1999-12-17 10:00:13 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
|
1999-09-22 03:32:33 -04:00
|
|
|
def helo( fromdom )
|
2000-03-27 10:52:27 -05:00
|
|
|
critical {
|
|
|
|
getok sprintf( 'HELO %s', fromdom )
|
|
|
|
}
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2000-02-21 10:25:37 -05:00
|
|
|
def ehlo( fromdom )
|
2000-03-27 10:52:27 -05:00
|
|
|
critical {
|
|
|
|
getok sprintf( 'EHLO %s', fromdom )
|
|
|
|
}
|
2000-02-21 10:25:37 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
|
1999-09-22 03:32:33 -04:00
|
|
|
def mailfrom( fromaddr )
|
2000-03-27 10:52:27 -05:00
|
|
|
critical {
|
|
|
|
getok sprintf( 'MAIL FROM:<%s>', fromaddr )
|
|
|
|
}
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def rcpt( toaddrs )
|
|
|
|
toaddrs.each do |i|
|
2000-03-27 10:52:27 -05:00
|
|
|
critical {
|
|
|
|
getok sprintf( 'RCPT TO:<%s>', i )
|
|
|
|
}
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def data
|
2000-03-27 10:52:27 -05:00
|
|
|
return unless begin_critical
|
1999-12-29 06:14:04 -05:00
|
|
|
getok 'DATA', ContinueCode
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2000-03-31 08:02:40 -05:00
|
|
|
def write_mail( mailsrc, block )
|
|
|
|
@socket.write_pendstr mailsrc, block
|
1999-12-29 06:14:04 -05:00
|
|
|
check_reply SuccessCode
|
2000-03-27 10:52:27 -05:00
|
|
|
end_critical
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
2000-02-21 10:25:37 -05:00
|
|
|
alias sendmail write_mail
|
1999-09-22 03:32:33 -04:00
|
|
|
|
|
|
|
|
2000-03-27 10:52:27 -05:00
|
|
|
def quit
|
|
|
|
critical {
|
|
|
|
getok 'QUIT'
|
|
|
|
}
|
|
|
|
end
|
1999-09-22 03:32:33 -04:00
|
|
|
|
|
|
|
|
2000-03-27 10:52:27 -05:00
|
|
|
private
|
1999-09-22 03:32:33 -04:00
|
|
|
|
|
|
|
|
|
|
|
def get_reply
|
|
|
|
arr = read_reply
|
|
|
|
stat = arr[0][0,3]
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
klass = UnknownCode
|
|
|
|
klass = case stat[0]
|
|
|
|
when ?2 then SuccessCode
|
|
|
|
when ?3 then ContinueCode
|
2000-03-31 08:02:40 -05:00
|
|
|
when ?4 then ServerErrorCode
|
1999-12-29 06:14:04 -05:00
|
|
|
when ?5 then
|
|
|
|
case stat[1]
|
|
|
|
when ?0 then SyntaxErrorCode
|
|
|
|
when ?5 then FatalErrorCode
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2000-03-31 08:02:40 -05:00
|
|
|
Response.new( klass, stat, arr.join('') )
|
1999-09-22 03:32:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def read_reply
|
|
|
|
arr = []
|
|
|
|
|
|
|
|
while (str = @socket.readline)[3] == ?- do # ex: "210-..."
|
|
|
|
arr.push str
|
|
|
|
end
|
|
|
|
arr.push str
|
|
|
|
|
|
|
|
return arr
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|