net-smtp 0.3.3 → 0.5.1
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/LICENSE.txt +2 -22
- data/NEWS.md +133 -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/auth_xoauth2.rb +17 -0
- data/lib/net/smtp/authenticator.rb +57 -0
- data/lib/net/smtp.rb +144 -192
- data/net-smtp.gemspec +4 -6
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc084bee5387c51eea4508e77ce6ccd2b220f4d090f91bccfb4fc3626142a3f2
|
4
|
+
data.tar.gz: a011fe3a47fc5119090e7beed0900e83f62b34c5ecbd7b2fe8453c2c7518cdd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29c4a47233280c89cc17360933fbdcd460c6b7e70e9023fda38ffa20f89d8afdbbd1c3cbf2d4f7db99e88aeea0e4dab5160a7b9f2d5638918372469fb531632b
|
7
|
+
data.tar.gz: a24a46eaada8bfe12b8e8e3f07e0db393a00c6db847581276f9a4263e334c93d29d31fc0792f80002415e9ace43059e160d22723bab89721b275b604cbdb83f3
|
data/LICENSE.txt
CHANGED
@@ -1,22 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
Redistribution and use in source and binary forms, with or without
|
4
|
-
modification, are permitted provided that the following conditions
|
5
|
-
are met:
|
6
|
-
1. Redistributions of source code must retain the above copyright
|
7
|
-
notice, this list of conditions and the following disclaimer.
|
8
|
-
2. Redistributions in binary form must reproduce the above copyright
|
9
|
-
notice, this list of conditions and the following disclaimer in the
|
10
|
-
documentation and/or other materials provided with the distribution.
|
11
|
-
|
12
|
-
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
13
|
-
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
14
|
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
15
|
-
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
16
|
-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
17
|
-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
18
|
-
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
19
|
-
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
20
|
-
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
21
|
-
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
22
|
-
SUCH DAMAGE.
|
1
|
+
All the files in this distribution are covered under either the Ruby license or
|
2
|
+
the BSD-2-Clause license (see the file COPYING).
|
data/NEWS.md
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
# NEWS
|
2
|
+
|
3
|
+
## Version 0.5.0 (2024-03-27)
|
4
|
+
|
5
|
+
### Improvements
|
6
|
+
|
7
|
+
* Allow case-insensitive strings for SASL mechanism <https://github.com/ruby/net-smtp/pull/64>
|
8
|
+
* Make #auth_capable? public <https://github.com/ruby/net-smtp/pull/63>
|
9
|
+
* Add XOAUTH2 authenticator <https://github.com/ruby/net-smtp/pull/80>
|
10
|
+
|
11
|
+
### Others
|
12
|
+
|
13
|
+
* Remove unused private auth_method <https://github.com/ruby/net-smtp/pull/67>
|
14
|
+
* Delegate checking auth args to the authenticator <https://github.com/ruby/net-smtp/pull/73>
|
15
|
+
* Updated docs, especially TLS and SASL-related <https://github.com/ruby/net-smtp/pull/66>
|
16
|
+
* Renew test certificates <https://github.com/ruby/net-smtp/pull/75>
|
17
|
+
* Fix version extraction to work with non ASCII characters with any LANG <https://github.com/ruby/net-smtp/pull/76>
|
18
|
+
* Replace non-ASCII EM DASH (U+2014) with ASCII hyphen (U+002D) <https://github.com/ruby/net-smtp/pull/78>
|
19
|
+
* Use reusing workflow for Ruby versions <https://github.com/ruby/net-smtp/pull/79>
|
20
|
+
* Make the test suite compatible with --enable-frozen-string-literal <https://github.com/ruby/net-smtp/pull/81>
|
21
|
+
|
22
|
+
## Version 0.4.0 (2023-09-20)
|
23
|
+
|
24
|
+
### Improvements
|
25
|
+
|
26
|
+
* add Net::SMTP::Authenticator class and auth_* methods are separated from the Net::SMTP class. <https://github.com/ruby/net-smtp/pull/53>
|
27
|
+
This allows you to add a new authentication method to Net::SMTP.
|
28
|
+
Create a class with an `auth` method that inherits Net::SMTP::Authenticator.
|
29
|
+
The `auth` method has two arguments, `user` and `secret`.
|
30
|
+
Send an instruction to the SMTP server by using the `continue` or `finish` method.
|
31
|
+
For more information, see lib/net/smtp/auto _*.rb.
|
32
|
+
* Add SMTPUTF8 support <https://github.com/ruby/net-smtp/pull/49>
|
33
|
+
|
34
|
+
### Fixes
|
35
|
+
|
36
|
+
* Revert "Replace Timeout.timeout with socket timeout" <https://github.com/ruby/net-smtp/pull/51>
|
37
|
+
* Fixed issue sending emails to unaffected recipients on 53x error <https://github.com/ruby/net-smtp/pull/56>
|
38
|
+
|
39
|
+
### Others
|
40
|
+
|
41
|
+
* Removed unnecessary Subversion keywords <https://github.com/ruby/net-smtp/pull/57>
|
42
|
+
|
43
|
+
## Version 0.3.3 (2022-10-29)
|
44
|
+
|
45
|
+
* No timeout library required <https://github.com/ruby/net-smtp/pull/44>
|
46
|
+
* Make the digest library optional <https://github.com/ruby/net-smtp/pull/45>
|
47
|
+
|
48
|
+
## Version 0.3.2 (2022-09-28)
|
49
|
+
|
50
|
+
* Make exception API compatible with what Ruby expects <https://github.com/ruby/net-smtp/pull/42>
|
51
|
+
|
52
|
+
## Version 0.3.1 (2021-12-12)
|
53
|
+
|
54
|
+
### Improvements
|
55
|
+
|
56
|
+
* add Net::SMTP::Address.
|
57
|
+
* add Net::SMTP#capable? and Net::SMTP#capabilities.
|
58
|
+
* add Net::SMTP#tls_verify, Net::SMTP#tls_hostname, Net::SMTP#ssl_context_params
|
59
|
+
|
60
|
+
## Version 0.3.0 (2021-10-14)
|
61
|
+
|
62
|
+
### Improvements
|
63
|
+
|
64
|
+
* Add `tls`, `starttls` keyword arguments.
|
65
|
+
```ruby
|
66
|
+
# always use TLS connection for port 465.
|
67
|
+
Net::SMTP.start(hostname, 465, tls: true)
|
68
|
+
|
69
|
+
# do not use starttls for localhost
|
70
|
+
Net::SMTP.start('localhost', starttls: false)
|
71
|
+
```
|
72
|
+
|
73
|
+
### Incompatible changes
|
74
|
+
|
75
|
+
* The tls_* paramter has been moved from start() to initialize().
|
76
|
+
|
77
|
+
## Version 0.2.2 (2021-10-09)
|
78
|
+
|
79
|
+
* Add `response` to SMTPError exceptions.
|
80
|
+
* `Net::SMTP.start()` and `#start()` accepts `ssl_context_params` keyword argument.
|
81
|
+
* Replace `Timeout.timeout` with socket timeout.
|
82
|
+
* Remove needless files from gem.
|
83
|
+
* Add dependency on digest, timeout.
|
84
|
+
|
85
|
+
## Version 0.2.1 (2020-11-18)
|
86
|
+
|
87
|
+
### Fixes
|
88
|
+
|
89
|
+
* Update the license for the default gems to dual licenses.
|
90
|
+
* Add dependency for net-protocol.
|
91
|
+
|
92
|
+
## Version 0.2.0 (2020-11-15)
|
93
|
+
|
94
|
+
### Incompatible changes
|
95
|
+
|
96
|
+
* Verify the server's certificate by default.
|
97
|
+
If you don't want verification, specify `start(tls_verify: false)`.
|
98
|
+
<https://github.com/ruby/net-smtp/pull/12>
|
99
|
+
|
100
|
+
* Use STARTTLS by default if possible.
|
101
|
+
If you don't want starttls, specify:
|
102
|
+
```
|
103
|
+
smtp = Net::SMTP.new(hostname, port)
|
104
|
+
smtp.disable_starttls
|
105
|
+
smtp.start do |s|
|
106
|
+
s.send_message ....
|
107
|
+
end
|
108
|
+
```
|
109
|
+
<https://github.com/ruby/net-smtp/pull/9>
|
110
|
+
|
111
|
+
### Improvements
|
112
|
+
|
113
|
+
* Net::SMTP.start and Net::SMTP#start arguments are keyword arguments.
|
114
|
+
```
|
115
|
+
start(address, port = nil, helo: 'localhost', user: nil, secret: nil, authtype: nil) { |smtp| ... }
|
116
|
+
```
|
117
|
+
`password` is an alias of `secret`.
|
118
|
+
<https://github.com/ruby/net-smtp/pull/7>
|
119
|
+
|
120
|
+
* Add `tls_hostname` parameter to `start()`.
|
121
|
+
If you want to use a different hostname than the certificate for the connection, you can specify the certificate hostname with `tls_hostname`.
|
122
|
+
<https://github.com/ruby/net-smtp/pull/14>
|
123
|
+
|
124
|
+
* Add SNI support to net/smtp <https://github.com/ruby/net-smtp/pull/4>
|
125
|
+
|
126
|
+
### Fixes
|
127
|
+
|
128
|
+
* enable_starttls before disable_tls causes an error. <https://github.com/ruby/net-smtp/pull/10>
|
129
|
+
* TLS should not check the hostname when verify_mode is disabled. <https://github.com/ruby/net-smtp/pull/6>
|
130
|
+
|
131
|
+
## Version 0.1.0 (2019-12-03)
|
132
|
+
|
133
|
+
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,17 @@
|
|
1
|
+
class Net::SMTP
|
2
|
+
class AuthXoauth2 < Net::SMTP::Authenticator
|
3
|
+
auth_type :xoauth2
|
4
|
+
|
5
|
+
def auth(user, secret)
|
6
|
+
token = xoauth2_string(user, secret)
|
7
|
+
|
8
|
+
finish("AUTH XOAUTH2 #{base64_encode(token)}")
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def xoauth2_string(user, secret)
|
14
|
+
"user=#{user}\1auth=Bearer #{secret}\1\1"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,57 @@
|
|
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
|
+
type = type.to_s.upcase.tr(?_, ?-).to_sym
|
10
|
+
Authenticator.auth_classes[type] = self
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.auth_class(type)
|
14
|
+
type = type.to_s.upcase.tr(?_, ?-).to_sym
|
15
|
+
Authenticator.auth_classes[type]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.check_args(user_arg = nil, secret_arg = nil, *, **)
|
19
|
+
unless user_arg
|
20
|
+
raise ArgumentError, 'SMTP-AUTH requested but missing user name'
|
21
|
+
end
|
22
|
+
unless secret_arg
|
23
|
+
raise ArgumentError, 'SMTP-AUTH requested but missing secret phrase'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :smtp
|
28
|
+
|
29
|
+
def initialize(smtp)
|
30
|
+
@smtp = smtp
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param arg [String] message to server
|
34
|
+
# @return [String] message from server
|
35
|
+
def continue(arg)
|
36
|
+
res = smtp.get_response arg
|
37
|
+
raise res.exception_class.new(res) unless res.continue?
|
38
|
+
res.string.split[1]
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param arg [String] message to server
|
42
|
+
# @return [Net::SMTP::Response] response from server
|
43
|
+
def finish(arg)
|
44
|
+
res = smtp.get_response arg
|
45
|
+
raise SMTPAuthenticationError.new(res) unless res.success?
|
46
|
+
res
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param str [String]
|
50
|
+
# @return [String] Base64 encoded string
|
51
|
+
def base64_encode(str)
|
52
|
+
# expects "str" may not become too long
|
53
|
+
[str].pack('m0')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
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,8 +13,6 @@
|
|
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
|
|
@@ -21,14 +20,9 @@ require 'net/protocol'
|
|
21
20
|
begin
|
22
21
|
require 'openssl'
|
23
22
|
rescue LoadError
|
24
|
-
begin
|
25
|
-
require 'digest/md5'
|
26
|
-
rescue LoadError
|
27
|
-
end
|
28
23
|
end
|
29
24
|
|
30
25
|
module Net
|
31
|
-
|
32
26
|
# Module mixed in to all SMTP error classes
|
33
27
|
module SMTPError
|
34
28
|
# This *class* is a module for backward compatibility.
|
@@ -42,7 +36,7 @@ module Net
|
|
42
36
|
@message = message
|
43
37
|
else
|
44
38
|
@response = nil
|
45
|
-
@message = message || response
|
39
|
+
@message = message || response
|
46
40
|
end
|
47
41
|
end
|
48
42
|
|
@@ -85,25 +79,34 @@ module Net
|
|
85
79
|
# == What is This Library?
|
86
80
|
#
|
87
81
|
# This library provides functionality to send internet
|
88
|
-
# mail via SMTP, the Simple Mail Transfer Protocol. For details of
|
89
|
-
# SMTP itself, see [
|
82
|
+
# mail via \SMTP, the Simple Mail Transfer Protocol. For details of
|
83
|
+
# \SMTP itself, see [RFC5321[https://www.rfc-editor.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[https://www.rfc-editor.org/rfc/rfc6409.html]],
|
88
|
+
# and [SMTPUTF8[https://www.rfc-editor.org/rfc/rfc6531.txt]], which is
|
89
|
+
# necessary to send messages to/from addresses containing characters
|
90
|
+
# outside the ASCII range.
|
90
91
|
#
|
91
92
|
# == What is This Library NOT?
|
92
93
|
#
|
93
94
|
# This library does NOT provide functions to compose internet mails.
|
94
95
|
# You must create them by yourself. If you want better mail support,
|
95
|
-
# try
|
96
|
+
# try the mail[https://rubygems.org/gems/mail] or
|
97
|
+
# rmail[https://rubygems.org/gems/rmail] gems, or search for alternatives in
|
96
98
|
# {RubyGems.org}[https://rubygems.org/] or {The Ruby
|
97
99
|
# Toolbox}[https://www.ruby-toolbox.com/].
|
98
100
|
#
|
99
|
-
# FYI: the official
|
101
|
+
# FYI: the official specification on internet mail is:
|
102
|
+
# [RFC5322[https://www.rfc-editor.org/rfc/rfc5322.txt]].
|
100
103
|
#
|
101
104
|
# == Examples
|
102
105
|
#
|
103
106
|
# === Sending Messages
|
104
107
|
#
|
105
|
-
# You must open a connection to an SMTP server before sending messages.
|
106
|
-
# The first argument is the address of your SMTP server, and the second
|
108
|
+
# You must open a connection to an \SMTP server before sending messages.
|
109
|
+
# The first argument is the address of your \SMTP server, and the second
|
107
110
|
# argument is the port number. Using SMTP.start with a block is the simplest
|
108
111
|
# way to do this. This way, the SMTP connection is closed automatically
|
109
112
|
# after the block is executed.
|
@@ -113,7 +116,7 @@ module Net
|
|
113
116
|
# # Use the SMTP object smtp only in this block.
|
114
117
|
# end
|
115
118
|
#
|
116
|
-
# Replace 'your.smtp.server' with your SMTP server. Normally
|
119
|
+
# Replace 'your.smtp.server' with your \SMTP server. Normally
|
117
120
|
# your system manager or internet provider supplies a server
|
118
121
|
# for you.
|
119
122
|
#
|
@@ -146,7 +149,7 @@ module Net
|
|
146
149
|
# smtp.send_message msgstr, 'from@address', 'to@address'
|
147
150
|
# smtp.finish
|
148
151
|
#
|
149
|
-
# You can also use the block form of SMTP.start
|
152
|
+
# You can also use the block form of SMTP.start or SMTP#start. This closes
|
150
153
|
# the SMTP session automatically:
|
151
154
|
#
|
152
155
|
# # using block form of SMTP.start
|
@@ -159,36 +162,37 @@ module Net
|
|
159
162
|
# === HELO domain
|
160
163
|
#
|
161
164
|
# In almost all situations, you must provide a third argument
|
162
|
-
# to SMTP.start
|
165
|
+
# to SMTP.start or SMTP#start. This is the domain name which you are on
|
163
166
|
# (the host to send mail from). It is called the "HELO domain".
|
164
|
-
# The SMTP server will judge whether it should send or reject
|
167
|
+
# The \SMTP server will judge whether it should send or reject
|
165
168
|
# the SMTP session by inspecting the HELO domain.
|
166
169
|
#
|
167
|
-
# Net::SMTP.start('your.smtp.server', 25
|
168
|
-
#
|
170
|
+
# Net::SMTP.start('your.smtp.server', 25, helo: 'mail.from.domain') do |smtp|
|
171
|
+
# smtp.send_message msgstr, 'from@address', 'to@address'
|
172
|
+
# end
|
173
|
+
#
|
174
|
+
# === \SMTP Authentication
|
169
175
|
#
|
170
|
-
#
|
176
|
+
# The Net::SMTP class supports the \SMTP extension for SASL Authentication
|
177
|
+
# [RFC4954[https://www.rfc-editor.org/rfc/rfc4954.html]] and the following
|
178
|
+
# SASL mechanisms: +PLAIN+, +LOGIN+ _(deprecated)_, and +CRAM-MD5+
|
179
|
+
# _(deprecated)_.
|
171
180
|
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
# To use SMTP authentication, pass extra arguments to
|
175
|
-
# SMTP.start/SMTP#start.
|
181
|
+
# To use \SMTP authentication, pass extra arguments to
|
182
|
+
# SMTP.start or SMTP#start.
|
176
183
|
#
|
177
184
|
# # PLAIN
|
178
|
-
# Net::SMTP.start('your.smtp.server', 25
|
185
|
+
# Net::SMTP.start('your.smtp.server', 25,
|
179
186
|
# user: 'Your Account', secret: 'Your Password', authtype: :plain)
|
180
|
-
# # LOGIN
|
181
|
-
# Net::SMTP.start('your.smtp.server', 25
|
182
|
-
# user: 'Your Account', secret: 'Your Password', authtype: :login)
|
183
187
|
#
|
184
|
-
#
|
185
|
-
#
|
186
|
-
#
|
188
|
+
# Support for other SASL mechanisms-such as +EXTERNAL+, +OAUTHBEARER+,
|
189
|
+
# +SCRAM-SHA-256+, and +XOAUTH2+-will be added in a future release.
|
190
|
+
#
|
191
|
+
# The +LOGIN+ and +CRAM-MD5+ mechanisms are still available for backwards
|
192
|
+
# compatibility, but are deprecated and should be avoided.
|
187
193
|
#
|
188
194
|
class SMTP < Protocol
|
189
|
-
VERSION = "0.
|
190
|
-
|
191
|
-
Revision = %q$Revision$.split[1]
|
195
|
+
VERSION = "0.5.1"
|
192
196
|
|
193
197
|
# The default SMTP port number, 25.
|
194
198
|
def SMTP.default_port
|
@@ -211,7 +215,7 @@ module Net
|
|
211
215
|
|
212
216
|
def SMTP.default_ssl_context(ssl_context_params = nil)
|
213
217
|
context = OpenSSL::SSL::SSLContext.new
|
214
|
-
context.set_params(ssl_context_params
|
218
|
+
context.set_params(ssl_context_params || {})
|
215
219
|
context
|
216
220
|
end
|
217
221
|
|
@@ -230,10 +234,13 @@ module Net
|
|
230
234
|
# If the hostname in the server certificate is different from +address+,
|
231
235
|
# it can be specified with +tls_hostname+.
|
232
236
|
#
|
233
|
-
# Additional SSLContext
|
234
|
-
# +
|
237
|
+
# Additional SSLContext[https://ruby.github.io/openssl/OpenSSL/SSL/SSLContext.html]
|
238
|
+
# params can be added to the +ssl_context_params+ hash argument and are
|
239
|
+
# passed to {OpenSSL::SSL::SSLContext#set_params}[https://ruby.github.io/openssl/OpenSSL/SSL/SSLContext.html#method-i-set_params].
|
240
|
+
#
|
241
|
+
# <tt>tls_verify: true</tt> is equivalent to <tt>ssl_context_params: {
|
242
|
+
# verify_mode: OpenSSL::SSL::VERIFY_PEER }</tt>.
|
235
243
|
#
|
236
|
-
# +tls_verify: true+ is equivalent to +ssl_context_params: { verify_mode: OpenSSL::SSL::VERIFY_PEER }+.
|
237
244
|
# This method does not open the TCP connection. You can use
|
238
245
|
# SMTP.start instead of SMTP.new if you want to do everything
|
239
246
|
# at once. Otherwise, follow SMTP.new with SMTP#start.
|
@@ -282,7 +289,7 @@ module Net
|
|
282
289
|
attr_accessor :esmtp
|
283
290
|
|
284
291
|
# +true+ if the SMTP object uses ESMTP (which it does by default).
|
285
|
-
alias
|
292
|
+
alias esmtp? esmtp
|
286
293
|
|
287
294
|
# true if server advertises STARTTLS.
|
288
295
|
# You cannot get valid value before opening SMTP session.
|
@@ -317,12 +324,13 @@ module Net
|
|
317
324
|
auth_capable?('CRAM-MD5')
|
318
325
|
end
|
319
326
|
|
327
|
+
# Returns whether the server advertises support for the authentication type.
|
328
|
+
# You cannot get valid result before opening SMTP session.
|
320
329
|
def auth_capable?(type)
|
321
330
|
return nil unless @capabilities
|
322
331
|
return false unless @capabilities['AUTH']
|
323
332
|
@capabilities['AUTH'].include?(type)
|
324
333
|
end
|
325
|
-
private :auth_capable?
|
326
334
|
|
327
335
|
# Returns supported authentication methods on this server.
|
328
336
|
# You cannot get valid value before opening SMTP session.
|
@@ -339,7 +347,7 @@ module Net
|
|
339
347
|
|
340
348
|
alias ssl? tls?
|
341
349
|
|
342
|
-
# Enables SMTP/TLS (SMTPS: SMTP over direct TLS connection) for
|
350
|
+
# Enables SMTP/TLS (SMTPS: \SMTP over direct TLS connection) for
|
343
351
|
# this object. Must be called before the connection is established
|
344
352
|
# to have any effect. +context+ is a OpenSSL::SSL::SSLContext object.
|
345
353
|
def enable_tls(context = nil)
|
@@ -458,7 +466,10 @@ module Net
|
|
458
466
|
#
|
459
467
|
# This method is equivalent to:
|
460
468
|
#
|
461
|
-
# Net::SMTP.new(address, port
|
469
|
+
# Net::SMTP.new(address, port, tls_verify: flag, tls_hostname: hostname, ssl_context_params: nil)
|
470
|
+
# .start(helo: helo_domain, user: account, secret: password, authtype: authtype)
|
471
|
+
#
|
472
|
+
# See also: Net::SMTP.new, #start
|
462
473
|
#
|
463
474
|
# === Example
|
464
475
|
#
|
@@ -483,12 +494,6 @@ module Net
|
|
483
494
|
# +helo+ is the _HELO_ _domain_ provided by the client to the
|
484
495
|
# server (see overview comments); it defaults to 'localhost'.
|
485
496
|
#
|
486
|
-
# The remaining arguments are used for SMTP authentication, if required
|
487
|
-
# or desired. +user+ is the account name; +secret+ is your password
|
488
|
-
# or other authentication token; and +authtype+ is the authentication
|
489
|
-
# type, one of :plain, :login, or :cram_md5. See the discussion of
|
490
|
-
# SMTP Authentication in the overview notes.
|
491
|
-
#
|
492
497
|
# If +tls+ is true, enable TLS. The default is false.
|
493
498
|
# If +starttls+ is :always, enable STARTTLS, if +:auto+, use STARTTLS when the server supports it,
|
494
499
|
# if false, disable STARTTLS.
|
@@ -497,10 +502,26 @@ module Net
|
|
497
502
|
# If the hostname in the server certificate is different from +address+,
|
498
503
|
# it can be specified with +tls_hostname+.
|
499
504
|
#
|
500
|
-
# Additional SSLContext
|
501
|
-
# +
|
505
|
+
# Additional SSLContext[https://ruby.github.io/openssl/OpenSSL/SSL/SSLContext.html]
|
506
|
+
# params can be added to the +ssl_context_params+ hash argument and are
|
507
|
+
# passed to {OpenSSL::SSL::SSLContext#set_params}[https://ruby.github.io/openssl/OpenSSL/SSL/SSLContext.html#method-i-set_params].
|
508
|
+
#
|
509
|
+
# <tt>tls_verify: true</tt> is equivalent to <tt>ssl_context_params: {
|
510
|
+
# verify_mode: OpenSSL::SSL::VERIFY_PEER }</tt>.
|
502
511
|
#
|
503
|
-
#
|
512
|
+
# The remaining arguments are used for \SMTP authentication, if required or
|
513
|
+
# desired.
|
514
|
+
#
|
515
|
+
# +authtype+ is the SASL authentication mechanism.
|
516
|
+
#
|
517
|
+
# +user+ is the authentication or authorization identity.
|
518
|
+
#
|
519
|
+
# +secret+ or +password+ is your password or other authentication token.
|
520
|
+
#
|
521
|
+
# These will be sent to #authenticate as positional arguments-the exact
|
522
|
+
# semantics are dependent on the +authtype+.
|
523
|
+
#
|
524
|
+
# See the discussion of Net::SMTP@SMTP+Authentication in the overview notes.
|
504
525
|
#
|
505
526
|
# === Errors
|
506
527
|
#
|
@@ -528,7 +549,7 @@ module Net
|
|
528
549
|
new(address, port, tls: tls, starttls: starttls, tls_verify: tls_verify, tls_hostname: tls_hostname, ssl_context_params: ssl_context_params).start(helo: helo, user: user, secret: secret, authtype: authtype, &block)
|
529
550
|
end
|
530
551
|
|
531
|
-
# +true+ if the SMTP session has been started.
|
552
|
+
# +true+ if the \SMTP session has been started.
|
532
553
|
def started?
|
533
554
|
@started
|
534
555
|
end
|
@@ -545,11 +566,21 @@ module Net
|
|
545
566
|
# +helo+ is the _HELO_ _domain_ that you'll dispatch mails from; see
|
546
567
|
# the discussion in the overview notes.
|
547
568
|
#
|
548
|
-
#
|
549
|
-
#
|
550
|
-
#
|
551
|
-
#
|
552
|
-
#
|
569
|
+
# The remaining arguments are used for \SMTP authentication, if required or
|
570
|
+
# desired.
|
571
|
+
#
|
572
|
+
# +authtype+ is the SASL authentication mechanism.
|
573
|
+
#
|
574
|
+
# +user+ is the authentication or authorization identity.
|
575
|
+
#
|
576
|
+
# +secret+ or +password+ is your password or other authentication token.
|
577
|
+
#
|
578
|
+
# These will be sent to #authenticate as positional arguments-the exact
|
579
|
+
# semantics are dependent on the +authtype+.
|
580
|
+
#
|
581
|
+
# See the discussion of Net::SMTP@SMTP+Authentication in the overview notes.
|
582
|
+
#
|
583
|
+
# See also: Net::SMTP.start
|
553
584
|
#
|
554
585
|
# === Block Usage
|
555
586
|
#
|
@@ -628,32 +659,18 @@ module Net
|
|
628
659
|
|
629
660
|
private
|
630
661
|
|
631
|
-
def digest_class
|
632
|
-
@digest_class ||= if defined?(OpenSSL::Digest)
|
633
|
-
OpenSSL::Digest
|
634
|
-
elsif defined?(::Digest)
|
635
|
-
::Digest
|
636
|
-
else
|
637
|
-
raise '"openssl" or "digest" library is required'
|
638
|
-
end
|
639
|
-
end
|
640
|
-
|
641
662
|
def tcp_socket(address, port)
|
642
|
-
|
643
|
-
Socket.tcp address, port, nil, nil, connect_timeout: @open_timeout
|
644
|
-
rescue Errno::ETIMEDOUT #raise Net:OpenTimeout instead for compatibility with previous versions
|
645
|
-
raise Net::OpenTimeout, "Timeout to open TCP connection to "\
|
646
|
-
"#{address}:#{port} (exceeds #{@open_timeout} seconds)"
|
647
|
-
end
|
663
|
+
TCPSocket.open address, port
|
648
664
|
end
|
649
665
|
|
650
666
|
def do_start(helo_domain, user, secret, authtype)
|
651
667
|
raise IOError, 'SMTP session already started' if @started
|
652
|
-
if user
|
653
|
-
|
654
|
-
|
668
|
+
if user || secret || authtype
|
669
|
+
check_auth_args authtype, user, secret
|
670
|
+
end
|
671
|
+
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) do
|
672
|
+
tcp_socket(@address, @port)
|
655
673
|
end
|
656
|
-
s = tcp_socket(@address, @port)
|
657
674
|
logging "Connection opened: #{@address}:#{@port}"
|
658
675
|
@socket = new_internet_message_io(tls? ? tlsconnect(s, @ssl_context_tls) : s)
|
659
676
|
check_response critical { recv_response() }
|
@@ -720,6 +737,18 @@ module Net
|
|
720
737
|
@socket = nil
|
721
738
|
end
|
722
739
|
|
740
|
+
def requires_smtputf8(address)
|
741
|
+
if address.kind_of? Address
|
742
|
+
!address.address.ascii_only?
|
743
|
+
else
|
744
|
+
!address.ascii_only?
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
def any_require_smtputf8(addresses)
|
749
|
+
addresses.any?{ |a| requires_smtputf8(a) }
|
750
|
+
end
|
751
|
+
|
723
752
|
#
|
724
753
|
# Message Sending
|
725
754
|
#
|
@@ -763,7 +792,9 @@ module Net
|
|
763
792
|
# * IOError
|
764
793
|
#
|
765
794
|
def send_message(msgstr, from_addr, *to_addrs)
|
795
|
+
to_addrs.flatten!
|
766
796
|
raise IOError, 'closed session' unless @socket
|
797
|
+
from_addr = Address.new(from_addr, 'SMTPUTF8') if any_require_smtputf8(to_addrs) && capable?('SMTPUTF8')
|
767
798
|
mailfrom from_addr
|
768
799
|
rcptto_list(to_addrs) {data msgstr}
|
769
800
|
end
|
@@ -816,7 +847,9 @@ module Net
|
|
816
847
|
# * IOError
|
817
848
|
#
|
818
849
|
def open_message_stream(from_addr, *to_addrs, &block) # :yield: stream
|
850
|
+
to_addrs.flatten!
|
819
851
|
raise IOError, 'closed session' unless @socket
|
852
|
+
from_addr = Address.new(from_addr, 'SMTPUTF8') if any_require_smtputf8(to_addrs) && capable?('SMTPUTF8')
|
820
853
|
mailfrom from_addr
|
821
854
|
rcptto_list(to_addrs) {data(&block)}
|
822
855
|
end
|
@@ -827,92 +860,28 @@ module Net
|
|
827
860
|
# Authentication
|
828
861
|
#
|
829
862
|
|
830
|
-
public
|
831
|
-
|
832
863
|
DEFAULT_AUTH_TYPE = :plain
|
833
864
|
|
865
|
+
# Authenticates with the server, using the "AUTH" command.
|
866
|
+
#
|
867
|
+
# +authtype+ is the name of a SASL authentication mechanism.
|
868
|
+
#
|
869
|
+
# All arguments-other than +authtype+-are forwarded to the authenticator.
|
870
|
+
# Different authenticators may interpret the +user+ and +secret+
|
871
|
+
# arguments differently.
|
834
872
|
def authenticate(user, secret, authtype = DEFAULT_AUTH_TYPE)
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
end
|
839
|
-
|
840
|
-
def auth_plain(user, secret)
|
841
|
-
check_auth_args user, secret
|
842
|
-
res = critical {
|
843
|
-
get_response('AUTH PLAIN ' + base64_encode("\0#{user}\0#{secret}"))
|
844
|
-
}
|
845
|
-
check_auth_response res
|
846
|
-
res
|
847
|
-
end
|
848
|
-
|
849
|
-
def auth_login(user, secret)
|
850
|
-
check_auth_args user, secret
|
851
|
-
res = critical {
|
852
|
-
check_auth_continue get_response('AUTH LOGIN')
|
853
|
-
check_auth_continue get_response(base64_encode(user))
|
854
|
-
get_response(base64_encode(secret))
|
855
|
-
}
|
856
|
-
check_auth_response res
|
857
|
-
res
|
858
|
-
end
|
859
|
-
|
860
|
-
def auth_cram_md5(user, secret)
|
861
|
-
check_auth_args user, secret
|
862
|
-
res = critical {
|
863
|
-
res0 = get_response('AUTH CRAM-MD5')
|
864
|
-
check_auth_continue res0
|
865
|
-
crammed = cram_md5_response(secret, res0.cram_md5_challenge)
|
866
|
-
get_response(base64_encode("#{user} #{crammed}"))
|
867
|
-
}
|
868
|
-
check_auth_response res
|
869
|
-
res
|
873
|
+
check_auth_args authtype, user, secret
|
874
|
+
authenticator = Authenticator.auth_class(authtype).new(self)
|
875
|
+
authenticator.auth(user, secret)
|
870
876
|
end
|
871
877
|
|
872
878
|
private
|
873
879
|
|
874
|
-
def
|
875
|
-
|
880
|
+
def check_auth_args(type, *args, **kwargs)
|
881
|
+
type ||= DEFAULT_AUTH_TYPE
|
882
|
+
klass = Authenticator.auth_class(type) or
|
876
883
|
raise ArgumentError, "wrong authentication type #{type}"
|
877
|
-
|
878
|
-
end
|
879
|
-
|
880
|
-
def auth_method(type)
|
881
|
-
"auth_#{type.to_s.downcase}".intern
|
882
|
-
end
|
883
|
-
|
884
|
-
def check_auth_args(user, secret, authtype = DEFAULT_AUTH_TYPE)
|
885
|
-
unless user
|
886
|
-
raise ArgumentError, 'SMTP-AUTH requested but missing user name'
|
887
|
-
end
|
888
|
-
unless secret
|
889
|
-
raise ArgumentError, 'SMTP-AUTH requested but missing secret phrase'
|
890
|
-
end
|
891
|
-
end
|
892
|
-
|
893
|
-
def base64_encode(str)
|
894
|
-
# expects "str" may not become too long
|
895
|
-
[str].pack('m0')
|
896
|
-
end
|
897
|
-
|
898
|
-
IMASK = 0x36
|
899
|
-
OMASK = 0x5c
|
900
|
-
|
901
|
-
# CRAM-MD5: [RFC2195]
|
902
|
-
def cram_md5_response(secret, challenge)
|
903
|
-
tmp = digest_class::MD5.digest(cram_secret(secret, IMASK) + challenge)
|
904
|
-
digest_class::MD5.hexdigest(cram_secret(secret, OMASK) + tmp)
|
905
|
-
end
|
906
|
-
|
907
|
-
CRAM_BUFSIZE = 64
|
908
|
-
|
909
|
-
def cram_secret(secret, mask)
|
910
|
-
secret = digest_class::MD5.digest(secret) if secret.size > CRAM_BUFSIZE
|
911
|
-
buf = secret.ljust(CRAM_BUFSIZE, "\0")
|
912
|
-
0.upto(buf.size - 1) do |i|
|
913
|
-
buf[i] = (buf[i].ord ^ mask).chr
|
914
|
-
end
|
915
|
-
buf
|
884
|
+
klass.check_args(*args, **kwargs)
|
916
885
|
end
|
917
886
|
|
918
887
|
#
|
@@ -941,29 +910,20 @@ module Net
|
|
941
910
|
|
942
911
|
# +from_addr+ is +String+ or +Net::SMTP::Address+
|
943
912
|
def mailfrom(from_addr)
|
944
|
-
addr =
|
913
|
+
addr = if requires_smtputf8(from_addr) && capable?("SMTPUTF8")
|
914
|
+
Address.new(from_addr, "SMTPUTF8")
|
915
|
+
else
|
916
|
+
Address.new(from_addr)
|
917
|
+
end
|
945
918
|
getok((["MAIL FROM:<#{addr.address}>"] + addr.parameters).join(' '))
|
946
919
|
end
|
947
920
|
|
948
921
|
def rcptto_list(to_addrs)
|
949
922
|
raise ArgumentError, 'mail destination not given' if to_addrs.empty?
|
950
|
-
ok_users = []
|
951
|
-
unknown_users = []
|
952
923
|
to_addrs.flatten.each do |addr|
|
953
|
-
|
954
|
-
rcptto addr
|
955
|
-
rescue SMTPAuthenticationError
|
956
|
-
unknown_users << addr.to_s.dump
|
957
|
-
else
|
958
|
-
ok_users << addr
|
959
|
-
end
|
924
|
+
rcptto addr
|
960
925
|
end
|
961
|
-
|
962
|
-
ret = yield
|
963
|
-
unless unknown_users.empty?
|
964
|
-
raise SMTPAuthenticationError, "failed to deliver for #{unknown_users.join(', ')}"
|
965
|
-
end
|
966
|
-
ret
|
926
|
+
yield
|
967
927
|
end
|
968
928
|
|
969
929
|
# +to_addr+ is +String+ or +Net::SMTP::Address+
|
@@ -1026,6 +986,12 @@ module Net
|
|
1026
986
|
getok('QUIT')
|
1027
987
|
end
|
1028
988
|
|
989
|
+
def get_response(reqline)
|
990
|
+
validate_line reqline
|
991
|
+
@socket.writeline reqline
|
992
|
+
recv_response()
|
993
|
+
end
|
994
|
+
|
1029
995
|
private
|
1030
996
|
|
1031
997
|
def validate_line(line)
|
@@ -1045,12 +1011,6 @@ module Net
|
|
1045
1011
|
res
|
1046
1012
|
end
|
1047
1013
|
|
1048
|
-
def get_response(reqline)
|
1049
|
-
validate_line reqline
|
1050
|
-
@socket.writeline reqline
|
1051
|
-
recv_response()
|
1052
|
-
end
|
1053
|
-
|
1054
1014
|
def recv_response
|
1055
1015
|
buf = ''.dup
|
1056
1016
|
while true
|
@@ -1083,18 +1043,6 @@ module Net
|
|
1083
1043
|
end
|
1084
1044
|
end
|
1085
1045
|
|
1086
|
-
def check_auth_response(res)
|
1087
|
-
unless res.success?
|
1088
|
-
raise SMTPAuthenticationError.new(res)
|
1089
|
-
end
|
1090
|
-
end
|
1091
|
-
|
1092
|
-
def check_auth_continue(res)
|
1093
|
-
unless res.continue?
|
1094
|
-
raise res.exception_class.new(res)
|
1095
|
-
end
|
1096
|
-
end
|
1097
|
-
|
1098
1046
|
# This class represents a response received by the SMTP server. Instances
|
1099
1047
|
# of this class are created by the SMTP class; they should not be directly
|
1100
1048
|
# created by the user. For more information on SMTP responses, view
|
@@ -1196,17 +1144,21 @@ module Net
|
|
1196
1144
|
@parameters = address.parameters
|
1197
1145
|
else
|
1198
1146
|
@address = address
|
1199
|
-
@parameters =
|
1147
|
+
@parameters = []
|
1200
1148
|
end
|
1149
|
+
@parameters = (parameters + args + [kw_args]).map{|param| Array(param)}.flatten(1).map{|param| Array(param).compact.join('=')}.uniq
|
1201
1150
|
end
|
1202
1151
|
|
1203
1152
|
def to_s
|
1204
1153
|
@address
|
1205
1154
|
end
|
1206
1155
|
end
|
1207
|
-
|
1208
1156
|
end # class SMTP
|
1209
1157
|
|
1210
1158
|
SMTPSession = SMTP # :nodoc:
|
1159
|
+
end
|
1211
1160
|
|
1161
|
+
require_relative 'smtp/authenticator'
|
1162
|
+
Dir.glob("#{__dir__}/smtp/auth_*.rb") do |r|
|
1163
|
+
require_relative r
|
1212
1164
|
end
|
data/net-smtp.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
name = File.basename(__FILE__, ".gemspec")
|
4
4
|
version = ["lib", Array.new(name.count("-"), "..").join("/")].find do |dir|
|
5
|
-
break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
|
5
|
+
break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb"), :encoding => "UTF-8") do |line|
|
6
6
|
/^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
|
7
7
|
end rescue nil
|
8
8
|
end
|
@@ -22,11 +22,9 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.metadata["homepage_uri"] = spec.homepage
|
23
23
|
spec.metadata["source_code_uri"] = spec.homepage
|
24
24
|
|
25
|
-
spec.files
|
26
|
-
LICENSE.txt
|
27
|
-
|
28
|
-
net-smtp.gemspec
|
29
|
-
]
|
25
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
26
|
+
`git ls-files README.md NEWS.md LICENSE.txt net-smtp.gemspec lib`.split
|
27
|
+
end
|
30
28
|
spec.require_paths = ["lib"]
|
31
29
|
|
32
30
|
spec.add_dependency "net-protocol"
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-smtp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yukihiro Matsumoto
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-02-05 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: net-protocol
|
@@ -32,7 +31,14 @@ extensions: []
|
|
32
31
|
extra_rdoc_files: []
|
33
32
|
files:
|
34
33
|
- LICENSE.txt
|
34
|
+
- NEWS.md
|
35
|
+
- README.md
|
35
36
|
- lib/net/smtp.rb
|
37
|
+
- lib/net/smtp/auth_cram_md5.rb
|
38
|
+
- lib/net/smtp/auth_login.rb
|
39
|
+
- lib/net/smtp/auth_plain.rb
|
40
|
+
- lib/net/smtp/auth_xoauth2.rb
|
41
|
+
- lib/net/smtp/authenticator.rb
|
36
42
|
- net-smtp.gemspec
|
37
43
|
homepage: https://github.com/ruby/net-smtp
|
38
44
|
licenses:
|
@@ -41,7 +47,6 @@ licenses:
|
|
41
47
|
metadata:
|
42
48
|
homepage_uri: https://github.com/ruby/net-smtp
|
43
49
|
source_code_uri: https://github.com/ruby/net-smtp
|
44
|
-
post_install_message:
|
45
50
|
rdoc_options: []
|
46
51
|
require_paths:
|
47
52
|
- lib
|
@@ -56,8 +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.
|
60
|
-
signing_key:
|
64
|
+
rubygems_version: 3.7.0.dev
|
61
65
|
specification_version: 4
|
62
66
|
summary: Simple Mail Transfer Protocol client library for Ruby.
|
63
67
|
test_files: []
|