net-smtp 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/NEWS.md +114 -0
- data/README.md +97 -0
- data/lib/net/smtp/auth_cram_md5.rb +48 -0
- data/lib/net/smtp/auth_login.rb +11 -0
- data/lib/net/smtp/auth_plain.rb +9 -0
- data/lib/net/smtp/authenticator.rb +46 -0
- data/lib/net/smtp.rb +56 -117
- metadata +9 -4
- data/net-smtp.gemspec +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0af9f3ec513aec9b2c9e9b59c086858e3ab6dfe4b66dced534439f3229661327
|
4
|
+
data.tar.gz: 307cd96a3a772e525294153b4e36d20fc7722cac80855a40cd9a2d0e11a21694
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9cd5a79d90ebb1d94872e25c416a539afebba68f322bec9953826e984f8e13ddd7403216fde5f09c2ef03a2b6a41cc2b5514b1697b7fd10fa7c663f202ed1fb8
|
7
|
+
data.tar.gz: a4d0b4d3749e98173aef3df7bcb2f0a0dd56a8404e801d4af68a38db31f02969f7f94ff659fe50d28b0dcc9f1083f03d0802c3954d9fe87141cf17abdf7777d9
|
data/NEWS.md
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
# NEWS
|
2
|
+
|
3
|
+
## Version 0.4.0 (2023-09-20)
|
4
|
+
|
5
|
+
### Improvements
|
6
|
+
|
7
|
+
* add Net::SMTP::Authenticator class and auth_* methods are separated from the Net::SMTP class. <https://github.com/ruby/net-smtp/pull/53>
|
8
|
+
This allows you to add a new authentication method to Net::SMTP.
|
9
|
+
Create a class with an `auth` method that inherits Net::SMTP::Authenticator.
|
10
|
+
The `auth` method has two arguments, `user` and `secret`.
|
11
|
+
Send an instruction to the SMTP server by using the `continue` or `finish` method.
|
12
|
+
For more information, see lib/net/smtp/auto _*.rb.
|
13
|
+
* Add SMTPUTF8 support <https://github.com/ruby/net-smtp/pull/49>
|
14
|
+
|
15
|
+
### Fixes
|
16
|
+
|
17
|
+
* Revert "Replace Timeout.timeout with socket timeout" <https://github.com/ruby/net-smtp/pull/51>
|
18
|
+
* Fixed issue sending emails to unaffected recipients on 53x error <https://github.com/ruby/net-smtp/pull/56>
|
19
|
+
|
20
|
+
### Others
|
21
|
+
|
22
|
+
* Removed unnecessary Subversion keywords <https://github.com/ruby/net-smtp/pull/57>
|
23
|
+
|
24
|
+
## Version 0.3.3 (2022-10-29)
|
25
|
+
|
26
|
+
* No timeout library required <https://github.com/ruby/net-smtp/pull/44>
|
27
|
+
* Make the digest library optional <https://github.com/ruby/net-smtp/pull/45>
|
28
|
+
|
29
|
+
## Version 0.3.2 (2022-09-28)
|
30
|
+
|
31
|
+
* Make exception API compatible with what Ruby expects <https://github.com/ruby/net-smtp/pull/42>
|
32
|
+
|
33
|
+
## Version 0.3.1 (2021-12-12)
|
34
|
+
|
35
|
+
### Improvements
|
36
|
+
|
37
|
+
* add Net::SMTP::Address.
|
38
|
+
* add Net::SMTP#capable? and Net::SMTP#capabilities.
|
39
|
+
* add Net::SMTP#tls_verify, Net::SMTP#tls_hostname, Net::SMTP#ssl_context_params
|
40
|
+
|
41
|
+
## Version 0.3.0 (2021-10-14)
|
42
|
+
|
43
|
+
### Improvements
|
44
|
+
|
45
|
+
* Add `tls`, `starttls` keyword arguments.
|
46
|
+
```ruby
|
47
|
+
# always use TLS connection for port 465.
|
48
|
+
Net::SMTP.start(hostname, 465, tls: true)
|
49
|
+
|
50
|
+
# do not use starttls for localhost
|
51
|
+
Net::SMTP.start('localhost', starttls: false)
|
52
|
+
```
|
53
|
+
|
54
|
+
### Incompatible changes
|
55
|
+
|
56
|
+
* The tls_* paramter has been moved from start() to initialize().
|
57
|
+
|
58
|
+
## Version 0.2.2 (2021-10-09)
|
59
|
+
|
60
|
+
* Add `response` to SMTPError exceptions.
|
61
|
+
* `Net::SMTP.start()` and `#start()` accepts `ssl_context_params` keyword argument.
|
62
|
+
* Replace `Timeout.timeout` with socket timeout.
|
63
|
+
* Remove needless files from gem.
|
64
|
+
* Add dependency on digest, timeout.
|
65
|
+
|
66
|
+
## Version 0.2.1 (2020-11-18)
|
67
|
+
|
68
|
+
### Fixes
|
69
|
+
|
70
|
+
* Update the license for the default gems to dual licenses.
|
71
|
+
* Add dependency for net-protocol.
|
72
|
+
|
73
|
+
## Version 0.2.0 (2020-11-15)
|
74
|
+
|
75
|
+
### Incompatible changes
|
76
|
+
|
77
|
+
* Verify the server's certificate by default.
|
78
|
+
If you don't want verification, specify `start(tls_verify: false)`.
|
79
|
+
<https://github.com/ruby/net-smtp/pull/12>
|
80
|
+
|
81
|
+
* Use STARTTLS by default if possible.
|
82
|
+
If you don't want starttls, specify:
|
83
|
+
```
|
84
|
+
smtp = Net::SMTP.new(hostname, port)
|
85
|
+
smtp.disable_starttls
|
86
|
+
smtp.start do |s|
|
87
|
+
s.send_message ....
|
88
|
+
end
|
89
|
+
```
|
90
|
+
<https://github.com/ruby/net-smtp/pull/9>
|
91
|
+
|
92
|
+
### Improvements
|
93
|
+
|
94
|
+
* Net::SMTP.start and Net::SMTP#start arguments are keyword arguments.
|
95
|
+
```
|
96
|
+
start(address, port = nil, helo: 'localhost', user: nil, secret: nil, authtype: nil) { |smtp| ... }
|
97
|
+
```
|
98
|
+
`password` is an alias of `secret`.
|
99
|
+
<https://github.com/ruby/net-smtp/pull/7>
|
100
|
+
|
101
|
+
* Add `tls_hostname` parameter to `start()`.
|
102
|
+
If you want to use a different hostname than the certificate for the connection, you can specify the certificate hostname with `tls_hostname`.
|
103
|
+
<https://github.com/ruby/net-smtp/pull/14>
|
104
|
+
|
105
|
+
* Add SNI support to net/smtp <https://github.com/ruby/net-smtp/pull/4>
|
106
|
+
|
107
|
+
### Fixes
|
108
|
+
|
109
|
+
* enable_starttls before disable_tls causes an error. <https://github.com/ruby/net-smtp/pull/10>
|
110
|
+
* TLS should not check the hostname when verify_mode is disabled. <https://github.com/ruby/net-smtp/pull/6>
|
111
|
+
|
112
|
+
## Version 0.1.0 (2019-12-03)
|
113
|
+
|
114
|
+
This is the first release of net-smtp gem.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# Net::SMTP
|
2
|
+
|
3
|
+
This library provides functionality to send internet mail via SMTP, the Simple Mail Transfer Protocol.
|
4
|
+
|
5
|
+
For details of SMTP itself, see [RFC2821](http://www.ietf.org/rfc/rfc2821.txt).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'net-smtp'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install net-smtp
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
### Sending Messages
|
26
|
+
|
27
|
+
You must open a connection to an SMTP server before sending messages.
|
28
|
+
The first argument is the address of your SMTP server, and the second
|
29
|
+
argument is the port number. Using SMTP.start with a block is the simplest
|
30
|
+
way to do this. This way, the SMTP connection is closed automatically
|
31
|
+
after the block is executed.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
require 'net/smtp'
|
35
|
+
Net::SMTP.start('your.smtp.server', 25) do |smtp|
|
36
|
+
# Use the SMTP object smtp only in this block.
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
Replace 'your.smtp.server' with your SMTP server. Normally
|
41
|
+
your system manager or internet provider supplies a server
|
42
|
+
for you.
|
43
|
+
|
44
|
+
Then you can send messages.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
msgstr = <<END_OF_MESSAGE
|
48
|
+
From: Your Name <your@mail.address>
|
49
|
+
To: Destination Address <someone@example.com>
|
50
|
+
Subject: test message
|
51
|
+
Date: Sat, 23 Jun 2001 16:26:43 +0900
|
52
|
+
Message-Id: <unique.message.id.string@example.com>
|
53
|
+
|
54
|
+
This is a test message.
|
55
|
+
END_OF_MESSAGE
|
56
|
+
|
57
|
+
require 'net/smtp'
|
58
|
+
Net::SMTP.start('your.smtp.server', 25) do |smtp|
|
59
|
+
smtp.send_message msgstr,
|
60
|
+
'your@mail.address',
|
61
|
+
'his_address@example.com'
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
### Closing the Session
|
66
|
+
|
67
|
+
You MUST close the SMTP session after sending messages, by calling
|
68
|
+
the #finish method:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
# using SMTP#finish
|
72
|
+
smtp = Net::SMTP.start('your.smtp.server', 25)
|
73
|
+
smtp.send_message msgstr, 'from@address', 'to@address'
|
74
|
+
smtp.finish
|
75
|
+
```
|
76
|
+
|
77
|
+
You can also use the block form of SMTP.start/SMTP#start. This closes
|
78
|
+
the SMTP session automatically:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
# using block form of SMTP.start
|
82
|
+
Net::SMTP.start('your.smtp.server', 25) do |smtp|
|
83
|
+
smtp.send_message msgstr, 'from@address', 'to@address'
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
I strongly recommend this scheme. This form is simpler and more robust.
|
88
|
+
|
89
|
+
## Development
|
90
|
+
|
91
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
92
|
+
|
93
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
94
|
+
|
95
|
+
## Contributing
|
96
|
+
|
97
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/net-smtp.
|
@@ -0,0 +1,48 @@
|
|
1
|
+
unless defined? OpenSSL
|
2
|
+
begin
|
3
|
+
require 'digest/md5'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Net::SMTP
|
9
|
+
class AuthCramMD5 < Net::SMTP::Authenticator
|
10
|
+
auth_type :cram_md5
|
11
|
+
|
12
|
+
def auth(user, secret)
|
13
|
+
challenge = continue('AUTH CRAM-MD5')
|
14
|
+
crammed = cram_md5_response(secret, challenge.unpack1('m'))
|
15
|
+
finish(base64_encode("#{user} #{crammed}"))
|
16
|
+
end
|
17
|
+
|
18
|
+
IMASK = 0x36
|
19
|
+
OMASK = 0x5c
|
20
|
+
|
21
|
+
# CRAM-MD5: [RFC2195]
|
22
|
+
def cram_md5_response(secret, challenge)
|
23
|
+
tmp = digest_class::MD5.digest(cram_secret(secret, IMASK) + challenge)
|
24
|
+
digest_class::MD5.hexdigest(cram_secret(secret, OMASK) + tmp)
|
25
|
+
end
|
26
|
+
|
27
|
+
CRAM_BUFSIZE = 64
|
28
|
+
|
29
|
+
def cram_secret(secret, mask)
|
30
|
+
secret = digest_class::MD5.digest(secret) if secret.size > CRAM_BUFSIZE
|
31
|
+
buf = secret.ljust(CRAM_BUFSIZE, "\0")
|
32
|
+
0.upto(buf.size - 1) do |i|
|
33
|
+
buf[i] = (buf[i].ord ^ mask).chr
|
34
|
+
end
|
35
|
+
buf
|
36
|
+
end
|
37
|
+
|
38
|
+
def digest_class
|
39
|
+
@digest_class ||= if defined?(OpenSSL::Digest)
|
40
|
+
OpenSSL::Digest
|
41
|
+
elsif defined?(::Digest)
|
42
|
+
::Digest
|
43
|
+
else
|
44
|
+
raise '"openssl" or "digest" library is required'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Net
|
2
|
+
class SMTP
|
3
|
+
class Authenticator
|
4
|
+
def self.auth_classes
|
5
|
+
@classes ||= {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.auth_type(type)
|
9
|
+
Authenticator.auth_classes[type] = self
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.auth_class(type)
|
13
|
+
Authenticator.auth_classes[type.intern]
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :smtp
|
17
|
+
|
18
|
+
def initialize(smtp)
|
19
|
+
@smtp = smtp
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param arg [String] message to server
|
23
|
+
# @return [String] message from server
|
24
|
+
def continue(arg)
|
25
|
+
res = smtp.get_response arg
|
26
|
+
raise res.exception_class.new(res) unless res.continue?
|
27
|
+
res.string.split[1]
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param arg [String] message to server
|
31
|
+
# @return [Net::SMTP::Response] response from server
|
32
|
+
def finish(arg)
|
33
|
+
res = smtp.get_response arg
|
34
|
+
raise SMTPAuthenticationError.new(res) unless res.success?
|
35
|
+
res
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param str [String]
|
39
|
+
# @return [String] Base64 encoded string
|
40
|
+
def base64_encode(str)
|
41
|
+
# expects "str" may not become too long
|
42
|
+
[str].pack('m0')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/net/smtp.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# = net/smtp.rb
|
3
4
|
#
|
4
5
|
# Copyright (c) 1999-2007 Yukihiro Matsumoto.
|
@@ -12,21 +13,16 @@
|
|
12
13
|
# This program is free software. You can re-distribute and/or
|
13
14
|
# modify this program under the same terms as Ruby itself.
|
14
15
|
#
|
15
|
-
# $Id$
|
16
|
-
#
|
17
16
|
# See Net::SMTP for documentation.
|
18
17
|
#
|
19
18
|
|
20
19
|
require 'net/protocol'
|
21
|
-
require 'digest/md5'
|
22
|
-
require 'timeout'
|
23
20
|
begin
|
24
21
|
require 'openssl'
|
25
22
|
rescue LoadError
|
26
23
|
end
|
27
24
|
|
28
25
|
module Net
|
29
|
-
|
30
26
|
# Module mixed in to all SMTP error classes
|
31
27
|
module SMTPError
|
32
28
|
# This *class* is a module for backward compatibility.
|
@@ -40,7 +36,7 @@ module Net
|
|
40
36
|
@message = message
|
41
37
|
else
|
42
38
|
@response = nil
|
43
|
-
@message = message || response
|
39
|
+
@message = message || response
|
44
40
|
end
|
45
41
|
end
|
46
42
|
|
@@ -84,7 +80,14 @@ module Net
|
|
84
80
|
#
|
85
81
|
# This library provides functionality to send internet
|
86
82
|
# mail via SMTP, the Simple Mail Transfer Protocol. For details of
|
87
|
-
# SMTP itself, see [
|
83
|
+
# SMTP itself, see [RFC5321] (http://www.ietf.org/rfc/rfc5321.txt).
|
84
|
+
# This library also implements SMTP authentication, which is often
|
85
|
+
# necessary for message composers to submit messages to their
|
86
|
+
# outgoing SMTP server, see
|
87
|
+
# [RFC6409](http://www.ietf.org/rfc/rfc6503.txt),
|
88
|
+
# and [SMTPUTF8](http://www.ietf.org/rfc/rfc6531.txt), which is
|
89
|
+
# necessary to send messages to/from addresses containing characters
|
90
|
+
# outside the ASCII range.
|
88
91
|
#
|
89
92
|
# == What is This Library NOT?
|
90
93
|
#
|
@@ -94,7 +97,7 @@ module Net
|
|
94
97
|
# {RubyGems.org}[https://rubygems.org/] or {The Ruby
|
95
98
|
# Toolbox}[https://www.ruby-toolbox.com/].
|
96
99
|
#
|
97
|
-
# FYI: the official
|
100
|
+
# FYI: the official specification on internet mail is: [RFC5322] (http://www.ietf.org/rfc/rfc5322.txt).
|
98
101
|
#
|
99
102
|
# == Examples
|
100
103
|
#
|
@@ -184,9 +187,7 @@ module Net
|
|
184
187
|
# user: 'Your Account', secret: 'Your Password', authtype: :cram_md5)
|
185
188
|
#
|
186
189
|
class SMTP < Protocol
|
187
|
-
VERSION = "0.
|
188
|
-
|
189
|
-
Revision = %q$Revision$.split[1]
|
190
|
+
VERSION = "0.4.0"
|
190
191
|
|
191
192
|
# The default SMTP port number, 25.
|
192
193
|
def SMTP.default_port
|
@@ -209,7 +210,7 @@ module Net
|
|
209
210
|
|
210
211
|
def SMTP.default_ssl_context(ssl_context_params = nil)
|
211
212
|
context = OpenSSL::SSL::SSLContext.new
|
212
|
-
context.set_params(ssl_context_params
|
213
|
+
context.set_params(ssl_context_params || {})
|
213
214
|
context
|
214
215
|
end
|
215
216
|
|
@@ -280,7 +281,7 @@ module Net
|
|
280
281
|
attr_accessor :esmtp
|
281
282
|
|
282
283
|
# +true+ if the SMTP object uses ESMTP (which it does by default).
|
283
|
-
alias
|
284
|
+
alias esmtp? esmtp
|
284
285
|
|
285
286
|
# true if server advertises STARTTLS.
|
286
287
|
# You cannot get valid value before opening SMTP session.
|
@@ -627,12 +628,7 @@ module Net
|
|
627
628
|
private
|
628
629
|
|
629
630
|
def tcp_socket(address, port)
|
630
|
-
|
631
|
-
Socket.tcp address, port, nil, nil, connect_timeout: @open_timeout
|
632
|
-
rescue Errno::ETIMEDOUT #raise Net:OpenTimeout instead for compatibility with previous versions
|
633
|
-
raise Net::OpenTimeout, "Timeout to open TCP connection to "\
|
634
|
-
"#{address}:#{port} (exceeds #{@open_timeout} seconds)"
|
635
|
-
end
|
631
|
+
TCPSocket.open address, port
|
636
632
|
end
|
637
633
|
|
638
634
|
def do_start(helo_domain, user, secret, authtype)
|
@@ -641,7 +637,9 @@ module Net
|
|
641
637
|
check_auth_method(authtype || DEFAULT_AUTH_TYPE)
|
642
638
|
check_auth_args user, secret
|
643
639
|
end
|
644
|
-
s =
|
640
|
+
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) do
|
641
|
+
tcp_socket(@address, @port)
|
642
|
+
end
|
645
643
|
logging "Connection opened: #{@address}:#{@port}"
|
646
644
|
@socket = new_internet_message_io(tls? ? tlsconnect(s, @ssl_context_tls) : s)
|
647
645
|
check_response critical { recv_response() }
|
@@ -708,6 +706,18 @@ module Net
|
|
708
706
|
@socket = nil
|
709
707
|
end
|
710
708
|
|
709
|
+
def requires_smtputf8(address)
|
710
|
+
if address.kind_of? Address
|
711
|
+
!address.address.ascii_only?
|
712
|
+
else
|
713
|
+
!address.ascii_only?
|
714
|
+
end
|
715
|
+
end
|
716
|
+
|
717
|
+
def any_require_smtputf8(addresses)
|
718
|
+
addresses.any?{ |a| requires_smtputf8(a) }
|
719
|
+
end
|
720
|
+
|
711
721
|
#
|
712
722
|
# Message Sending
|
713
723
|
#
|
@@ -751,7 +761,9 @@ module Net
|
|
751
761
|
# * IOError
|
752
762
|
#
|
753
763
|
def send_message(msgstr, from_addr, *to_addrs)
|
764
|
+
to_addrs.flatten!
|
754
765
|
raise IOError, 'closed session' unless @socket
|
766
|
+
from_addr = Address.new(from_addr, 'SMTPUTF8') if any_require_smtputf8(to_addrs) && capable?('SMTPUTF8')
|
755
767
|
mailfrom from_addr
|
756
768
|
rcptto_list(to_addrs) {data msgstr}
|
757
769
|
end
|
@@ -804,7 +816,9 @@ module Net
|
|
804
816
|
# * IOError
|
805
817
|
#
|
806
818
|
def open_message_stream(from_addr, *to_addrs, &block) # :yield: stream
|
819
|
+
to_addrs.flatten!
|
807
820
|
raise IOError, 'closed session' unless @socket
|
821
|
+
from_addr = Address.new(from_addr, 'SMTPUTF8') if any_require_smtputf8(to_addrs) && capable?('SMTPUTF8')
|
808
822
|
mailfrom from_addr
|
809
823
|
rcptto_list(to_addrs) {data(&block)}
|
810
824
|
end
|
@@ -815,52 +829,19 @@ module Net
|
|
815
829
|
# Authentication
|
816
830
|
#
|
817
831
|
|
818
|
-
public
|
819
|
-
|
820
832
|
DEFAULT_AUTH_TYPE = :plain
|
821
833
|
|
822
834
|
def authenticate(user, secret, authtype = DEFAULT_AUTH_TYPE)
|
823
835
|
check_auth_method authtype
|
824
836
|
check_auth_args user, secret
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
def auth_plain(user, secret)
|
829
|
-
check_auth_args user, secret
|
830
|
-
res = critical {
|
831
|
-
get_response('AUTH PLAIN ' + base64_encode("\0#{user}\0#{secret}"))
|
832
|
-
}
|
833
|
-
check_auth_response res
|
834
|
-
res
|
835
|
-
end
|
836
|
-
|
837
|
-
def auth_login(user, secret)
|
838
|
-
check_auth_args user, secret
|
839
|
-
res = critical {
|
840
|
-
check_auth_continue get_response('AUTH LOGIN')
|
841
|
-
check_auth_continue get_response(base64_encode(user))
|
842
|
-
get_response(base64_encode(secret))
|
843
|
-
}
|
844
|
-
check_auth_response res
|
845
|
-
res
|
846
|
-
end
|
847
|
-
|
848
|
-
def auth_cram_md5(user, secret)
|
849
|
-
check_auth_args user, secret
|
850
|
-
res = critical {
|
851
|
-
res0 = get_response('AUTH CRAM-MD5')
|
852
|
-
check_auth_continue res0
|
853
|
-
crammed = cram_md5_response(secret, res0.cram_md5_challenge)
|
854
|
-
get_response(base64_encode("#{user} #{crammed}"))
|
855
|
-
}
|
856
|
-
check_auth_response res
|
857
|
-
res
|
837
|
+
authenticator = Authenticator.auth_class(authtype).new(self)
|
838
|
+
authenticator.auth(user, secret)
|
858
839
|
end
|
859
840
|
|
860
841
|
private
|
861
842
|
|
862
843
|
def check_auth_method(type)
|
863
|
-
unless
|
844
|
+
unless Authenticator.auth_class(type)
|
864
845
|
raise ArgumentError, "wrong authentication type #{type}"
|
865
846
|
end
|
866
847
|
end
|
@@ -878,31 +859,6 @@ module Net
|
|
878
859
|
end
|
879
860
|
end
|
880
861
|
|
881
|
-
def base64_encode(str)
|
882
|
-
# expects "str" may not become too long
|
883
|
-
[str].pack('m0')
|
884
|
-
end
|
885
|
-
|
886
|
-
IMASK = 0x36
|
887
|
-
OMASK = 0x5c
|
888
|
-
|
889
|
-
# CRAM-MD5: [RFC2195]
|
890
|
-
def cram_md5_response(secret, challenge)
|
891
|
-
tmp = Digest::MD5.digest(cram_secret(secret, IMASK) + challenge)
|
892
|
-
Digest::MD5.hexdigest(cram_secret(secret, OMASK) + tmp)
|
893
|
-
end
|
894
|
-
|
895
|
-
CRAM_BUFSIZE = 64
|
896
|
-
|
897
|
-
def cram_secret(secret, mask)
|
898
|
-
secret = Digest::MD5.digest(secret) if secret.size > CRAM_BUFSIZE
|
899
|
-
buf = secret.ljust(CRAM_BUFSIZE, "\0")
|
900
|
-
0.upto(buf.size - 1) do |i|
|
901
|
-
buf[i] = (buf[i].ord ^ mask).chr
|
902
|
-
end
|
903
|
-
buf
|
904
|
-
end
|
905
|
-
|
906
862
|
#
|
907
863
|
# SMTP command dispatcher
|
908
864
|
#
|
@@ -929,29 +885,20 @@ module Net
|
|
929
885
|
|
930
886
|
# +from_addr+ is +String+ or +Net::SMTP::Address+
|
931
887
|
def mailfrom(from_addr)
|
932
|
-
addr =
|
888
|
+
addr = if requires_smtputf8(from_addr) && capable?("SMTPUTF8")
|
889
|
+
Address.new(from_addr, "SMTPUTF8")
|
890
|
+
else
|
891
|
+
Address.new(from_addr)
|
892
|
+
end
|
933
893
|
getok((["MAIL FROM:<#{addr.address}>"] + addr.parameters).join(' '))
|
934
894
|
end
|
935
895
|
|
936
896
|
def rcptto_list(to_addrs)
|
937
897
|
raise ArgumentError, 'mail destination not given' if to_addrs.empty?
|
938
|
-
ok_users = []
|
939
|
-
unknown_users = []
|
940
898
|
to_addrs.flatten.each do |addr|
|
941
|
-
|
942
|
-
rcptto addr
|
943
|
-
rescue SMTPAuthenticationError
|
944
|
-
unknown_users << addr.to_s.dump
|
945
|
-
else
|
946
|
-
ok_users << addr
|
947
|
-
end
|
948
|
-
end
|
949
|
-
raise ArgumentError, 'mail destination not given' if ok_users.empty?
|
950
|
-
ret = yield
|
951
|
-
unless unknown_users.empty?
|
952
|
-
raise SMTPAuthenticationError, "failed to deliver for #{unknown_users.join(', ')}"
|
899
|
+
rcptto addr
|
953
900
|
end
|
954
|
-
|
901
|
+
yield
|
955
902
|
end
|
956
903
|
|
957
904
|
# +to_addr+ is +String+ or +Net::SMTP::Address+
|
@@ -1014,6 +961,12 @@ module Net
|
|
1014
961
|
getok('QUIT')
|
1015
962
|
end
|
1016
963
|
|
964
|
+
def get_response(reqline)
|
965
|
+
validate_line reqline
|
966
|
+
@socket.writeline reqline
|
967
|
+
recv_response()
|
968
|
+
end
|
969
|
+
|
1017
970
|
private
|
1018
971
|
|
1019
972
|
def validate_line(line)
|
@@ -1033,12 +986,6 @@ module Net
|
|
1033
986
|
res
|
1034
987
|
end
|
1035
988
|
|
1036
|
-
def get_response(reqline)
|
1037
|
-
validate_line reqline
|
1038
|
-
@socket.writeline reqline
|
1039
|
-
recv_response()
|
1040
|
-
end
|
1041
|
-
|
1042
989
|
def recv_response
|
1043
990
|
buf = ''.dup
|
1044
991
|
while true
|
@@ -1071,18 +1018,6 @@ module Net
|
|
1071
1018
|
end
|
1072
1019
|
end
|
1073
1020
|
|
1074
|
-
def check_auth_response(res)
|
1075
|
-
unless res.success?
|
1076
|
-
raise SMTPAuthenticationError.new(res)
|
1077
|
-
end
|
1078
|
-
end
|
1079
|
-
|
1080
|
-
def check_auth_continue(res)
|
1081
|
-
unless res.continue?
|
1082
|
-
raise res.exception_class.new(res)
|
1083
|
-
end
|
1084
|
-
end
|
1085
|
-
|
1086
1021
|
# This class represents a response received by the SMTP server. Instances
|
1087
1022
|
# of this class are created by the SMTP class; they should not be directly
|
1088
1023
|
# created by the user. For more information on SMTP responses, view
|
@@ -1184,17 +1119,21 @@ module Net
|
|
1184
1119
|
@parameters = address.parameters
|
1185
1120
|
else
|
1186
1121
|
@address = address
|
1187
|
-
@parameters =
|
1122
|
+
@parameters = []
|
1188
1123
|
end
|
1124
|
+
@parameters = (parameters + args + [kw_args]).map{|param| Array(param)}.flatten(1).map{|param| Array(param).compact.join('=')}.uniq
|
1189
1125
|
end
|
1190
1126
|
|
1191
1127
|
def to_s
|
1192
1128
|
@address
|
1193
1129
|
end
|
1194
1130
|
end
|
1195
|
-
|
1196
1131
|
end # class SMTP
|
1197
1132
|
|
1198
1133
|
SMTPSession = SMTP # :nodoc:
|
1134
|
+
end
|
1199
1135
|
|
1136
|
+
require_relative 'smtp/authenticator'
|
1137
|
+
Dir.glob("#{__dir__}/smtp/auth_*.rb") do |r|
|
1138
|
+
require_relative r
|
1200
1139
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-smtp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yukihiro Matsumoto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-protocol
|
@@ -32,8 +32,13 @@ extensions: []
|
|
32
32
|
extra_rdoc_files: []
|
33
33
|
files:
|
34
34
|
- LICENSE.txt
|
35
|
+
- NEWS.md
|
36
|
+
- README.md
|
35
37
|
- lib/net/smtp.rb
|
36
|
-
- net
|
38
|
+
- lib/net/smtp/auth_cram_md5.rb
|
39
|
+
- lib/net/smtp/auth_login.rb
|
40
|
+
- lib/net/smtp/auth_plain.rb
|
41
|
+
- lib/net/smtp/authenticator.rb
|
37
42
|
homepage: https://github.com/ruby/net-smtp
|
38
43
|
licenses:
|
39
44
|
- Ruby
|
@@ -56,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
61
|
- !ruby/object:Gem::Version
|
57
62
|
version: '0'
|
58
63
|
requirements: []
|
59
|
-
rubygems_version: 3.
|
64
|
+
rubygems_version: 3.5.0.dev
|
60
65
|
signing_key:
|
61
66
|
specification_version: 4
|
62
67
|
summary: Simple Mail Transfer Protocol client library for Ruby.
|
data/net-smtp.gemspec
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
name = File.basename(__FILE__, ".gemspec")
|
4
|
-
version = ["lib", Array.new(name.count("-"), "..").join("/")].find do |dir|
|
5
|
-
break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
|
6
|
-
/^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
|
7
|
-
end rescue nil
|
8
|
-
end
|
9
|
-
|
10
|
-
Gem::Specification.new do |spec|
|
11
|
-
spec.name = name
|
12
|
-
spec.version = version
|
13
|
-
spec.authors = ["Yukihiro Matsumoto"]
|
14
|
-
spec.email = ["matz@ruby-lang.org"]
|
15
|
-
|
16
|
-
spec.summary = %q{Simple Mail Transfer Protocol client library for Ruby.}
|
17
|
-
spec.description = %q{Simple Mail Transfer Protocol client library for Ruby.}
|
18
|
-
spec.homepage = "https://github.com/ruby/net-smtp"
|
19
|
-
spec.licenses = ["Ruby", "BSD-2-Clause"]
|
20
|
-
spec.required_ruby_version = ">= 2.6.0"
|
21
|
-
|
22
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
23
|
-
spec.metadata["source_code_uri"] = spec.homepage
|
24
|
-
|
25
|
-
spec.files = %w[
|
26
|
-
LICENSE.txt
|
27
|
-
lib/net/smtp.rb
|
28
|
-
net-smtp.gemspec
|
29
|
-
]
|
30
|
-
spec.require_paths = ["lib"]
|
31
|
-
|
32
|
-
spec.add_dependency "net-protocol"
|
33
|
-
end
|