3 = net/smtp.rb version 1.1.35
5 Copyright (c) 1999-2001 Yukihiro Matsumoto
7 written & maintained by Minero Aoki <aamine@loveruby.net>
9 This program is free software. You can re-distribute and/or
10 modify this program under the same terms as Ruby itself,
11 Ruby Distribute License or GNU General Public License.
13 NOTE: You can get Japanese version of this document from
14 Ruby Documentation Project (RDP):
15 ((<URL:http://www.ruby-lang.org/~rubikitch/RDP.cgi>))
17 == What is This Module?
19 This module provides your program the functions to send internet
20 mail via SMTP, Simple Mail Transfer Protocol. For details of
21 SMTP itself, refer [RFC2821] ((<URL:http://www.ietf.org/rfc/rfc2821.txt>)).
23 == What This Module is NOT?
25 This module does NOT provide the functions to compose internet
26 mail. You must create it by yourself. For details of internet mail
27 format, see [RFC2822] ((<URL:http://www.ietf.org/rfc/rfc2822.txt>)).
33 You must open connection to SMTP server before sending mails.
34 First argument is the address of SMTP server, and second argument
35 is port number. Using SMTP.start with block is the most simple way
36 to do it. SMTP Connection is closed automatically after block is
40 Net::SMTP.start( 'your.smtp.server', 25 ) {|smtp|
41 # use smtp object only in this block
44 Replace 'your.smtp.server' by your SMTP server. Normally
45 your system manager or internet provider is supplying a server
48 Then you can send mail.
52 Net::SMTP.start( 'your.smtp.server', 25 ) {|smtp|
53 smtp.send_mail <<EndOfMail, 'your@mail.address', 'to@some.domain'
54 From: Your Name <your@mail.address>
55 To: Dest Address <to@some.domain>
57 Date: Sat, 23 Jun 2001 16:26:43 +0900
58 Message-Id: <unique.message.id.string@some.domain>
64 === Sending Mails from Any Sources
66 In an example above I sent mail from String (here document literal).
67 SMTP#send_mail accepts any objects which has "each" method
71 Net::SMTP.start( 'your.smtp.server', 25 ) {|smtp|
72 File.open( 'Mail/draft/1' ) {|f|
73 smtp.send_mail f, 'your@mail.address', 'to@some.domain'
77 === Giving "Hello" Domain
79 If your machine does not have canonical host name, maybe you
80 must designate the third argument of SMTP.start.
82 Net::SMTP.start( 'your.smtp.server', 25,
83 'mail.from.domain' ) {|smtp|
85 This argument gives MAILFROM domain, the domain name that
86 you send mail from. SMTP server might judge if he (or she?)
87 send or reject SMTP session by this data.
93 : new( address = 'localhost', port = 25 )
94 creates a new Net::SMTP object.
96 : start( address = 'localhost', port = 25, helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil )
97 : start( address = 'localhost', port = 25, helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil ) {|smtp| .... }
99 Net::SMTP.new(address,port).start(helo_domain,account,password,authtype)
102 Net::SMTP.start( 'your.smtp.server' ) {
103 smtp.send_mail mail_string, 'from@mail.address', 'dest@mail.address'
108 : start( helo_domain = <local host name>, account = nil, password = nil, authtype = nil )
109 : start( helo_domain = <local host name>, account = nil, password = nil, authtype = nil ) {|smtp| .... }
110 opens TCP connection and starts SMTP session.
111 If protocol had been started, do nothing and return false.
112 HELO_DOMAIN is a domain that you'll dispatch mails from.
114 When this methods is called with block, give a SMTP object to block and
115 close session after block call finished.
117 If both of account and password are given, is trying to get
118 authentication by using AUTH command. :plain or :cram_md5 is
119 allowed for AUTHTYPE.
122 true if SMTP session is started.
125 the address to connect
128 the port number to connect
132 seconds to wait until connection is opened.
133 If SMTP object cannot open a conection in this seconds,
134 it raises TimeoutError exception.
138 seconds to wait until reading one block (by one read(1) call).
139 If SMTP object cannot open a conection in this seconds,
140 it raises TimeoutError exception.
143 finishes SMTP session.
144 If SMTP session had not started, do nothing and return false.
146 : send_mail( mailsrc, from_addr, *to_addrs )
147 This method sends MAILSRC as mail. A SMTP object read strings
148 from MAILSRC by calling "each" iterator, with converting them
149 into CRLF ("\r\n") terminated string when write.
151 FROM_ADDR must be a String, representing source mail address.
152 TO_ADDRS must be Strings or an Array of Strings, representing
153 destination mail addresses.
156 Net::SMTP.start( 'your.smtp.server' ) {|smtp|
157 smtp.send_mail mail_string,
159 'dest@mail.address' 'dest2@mail.address'
162 : ready( from_addr, *to_addrs ) {|adapter| .... }
163 This method stands by the SMTP object for sending mail and
164 give adapter object to the block. ADAPTER accepts only "write"
167 FROM_ADDR must be a String, representing source mail address.
168 TO_ADDRS must be Strings or an Array of Strings, representing
169 destination mail addresses.
172 Net::SMTP.start( 'your.smtp.server', 25 ) {|smtp|
173 smtp.ready( 'from@mail.addr', 'dest@mail.addr' ) do |adapter|
182 SMTP objects raise these exceptions:
183 : Net::ProtoSyntaxError
184 syntax error (errno.500)
185 : Net::ProtoFatalError
186 fatal error (errno.550)
187 : Net::ProtoUnknownError
188 unknown error. (is probably bug)
189 : Net::ProtoServerBusy
190 temporary error (errno.420/450)
194 require 'net/protocol'
201 class SMTP < Protocol
203 protocol_param :port, '25'
204 protocol_param :command_type, '::Net::NetPrivate::SMTPCommand'
207 def initialize( addr = nil, port = nil )
214 def send_mail( mailsrc, from_addr, *to_addrs )
215 do_ready from_addr, to_addrs.flatten
216 @command.write_mail mailsrc, nil
219 alias sendmail send_mail
221 def ready( from_addr, *to_addrs, &block )
222 do_ready from_addr, to_addrs.flatten
223 @command.write_mail nil, block
230 def do_ready( from_addr, to_addrs )
231 if to_addrs.empty? then
232 raise ArgumentError, 'mail destination does not given'
234 @command.mailfrom from_addr
235 @command.rcpt to_addrs
239 def do_start( helodom = nil,
240 user = nil, secret = nil, authtype = nil )
241 helodom ||= ::Socket.gethostname
244 "cannot get localhost name; try 'smtp.start(local_host_name)'"
249 @command.ehlo helodom
251 @command.helo helodom
263 if user or secret then
265 raise ArgumentError, 'both of account and password are required'
267 mid = 'auth_' + (authtype || 'cram_md5').to_s
268 @command.respond_to? mid or
269 raise ArgumentError, "wrong auth type #{authtype.to_s}"
271 @command.__send__ mid, user, secret
284 class SMTPCommand < Command
286 def initialize( sock )
289 check_reply SuccessCode
296 getok sprintf( 'HELO %s', fromdom )
303 getok sprintf( 'EHLO %s', fromdom )
308 # "PLAIN" authentication [RFC2554]
309 def auth_plain( user, secret )
311 getok sprintf( 'AUTH PLAIN %s',
312 ["\0#{user}\0#{secret}"].pack('m').chomp )
316 # "CRAM-MD5" authentication [RFC2195]
317 def auth_cram_md5( user, secret )
319 rep = getok( 'AUTH CRAM-MD5', ContinueCode )
320 challenge = rep.msg.split(' ')[1].unpack('m')[0]
321 secret = MD5.new( secret ).digest if secret.size > 64
323 isecret = secret + "\0" * (64 - secret.size)
324 osecret = isecret.dup
329 tmp = MD5.new( isecret + challenge ).digest
330 tmp = MD5.new( osecret + tmp ).hexdigest
332 getok [user + ' ' + tmp].pack('m').chomp
337 def mailfrom( fromaddr )
339 getok sprintf( 'MAIL FROM:<%s>', fromaddr )
347 getok sprintf( 'RCPT TO:<%s>', i )
354 return unless begin_critical
355 getok 'DATA', ContinueCode
358 def write_mail( mailsrc, block )
359 @socket.write_pendstr mailsrc, block
360 check_reply SuccessCode
380 when ?2 then SuccessCode
381 when ?3 then ContinueCode
382 when ?4 then ServerErrorCode
385 when ?0 then SyntaxErrorCode
386 when ?3 then AuthErrorCode
387 when ?5 then FatalErrorCode
390 klass ||= UnknownCode
392 Response.new( klass, stat, arr.join('') )
399 str = @socket.readline
400 break unless str[3] == ?- # ex: "210-..."
411 end # module Net::NetPrivate