net-smtp 0.3.4 → 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 -129
- 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,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
|
|
@@ -86,7 +80,14 @@ module Net
|
|
86
80
|
#
|
87
81
|
# This library provides functionality to send internet
|
88
82
|
# mail via SMTP, the Simple Mail Transfer Protocol. For details of
|
89
|
-
# 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.
|
90
91
|
#
|
91
92
|
# == What is This Library NOT?
|
92
93
|
#
|
@@ -96,7 +97,7 @@ module Net
|
|
96
97
|
# {RubyGems.org}[https://rubygems.org/] or {The Ruby
|
97
98
|
# Toolbox}[https://www.ruby-toolbox.com/].
|
98
99
|
#
|
99
|
-
# FYI: the official
|
100
|
+
# FYI: the official specification on internet mail is: [RFC5322] (http://www.ietf.org/rfc/rfc5322.txt).
|
100
101
|
#
|
101
102
|
# == Examples
|
102
103
|
#
|
@@ -186,9 +187,7 @@ module Net
|
|
186
187
|
# user: 'Your Account', secret: 'Your Password', authtype: :cram_md5)
|
187
188
|
#
|
188
189
|
class SMTP < Protocol
|
189
|
-
VERSION = "0.
|
190
|
-
|
191
|
-
Revision = %q$Revision$.split[1]
|
190
|
+
VERSION = "0.4.0"
|
192
191
|
|
193
192
|
# The default SMTP port number, 25.
|
194
193
|
def SMTP.default_port
|
@@ -211,7 +210,7 @@ module Net
|
|
211
210
|
|
212
211
|
def SMTP.default_ssl_context(ssl_context_params = nil)
|
213
212
|
context = OpenSSL::SSL::SSLContext.new
|
214
|
-
context.set_params(ssl_context_params
|
213
|
+
context.set_params(ssl_context_params || {})
|
215
214
|
context
|
216
215
|
end
|
217
216
|
|
@@ -282,7 +281,7 @@ module Net
|
|
282
281
|
attr_accessor :esmtp
|
283
282
|
|
284
283
|
# +true+ if the SMTP object uses ESMTP (which it does by default).
|
285
|
-
alias
|
284
|
+
alias esmtp? esmtp
|
286
285
|
|
287
286
|
# true if server advertises STARTTLS.
|
288
287
|
# You cannot get valid value before opening SMTP session.
|
@@ -628,23 +627,8 @@ module Net
|
|
628
627
|
|
629
628
|
private
|
630
629
|
|
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
630
|
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
|
631
|
+
TCPSocket.open address, port
|
648
632
|
end
|
649
633
|
|
650
634
|
def do_start(helo_domain, user, secret, authtype)
|
@@ -653,7 +637,9 @@ module Net
|
|
653
637
|
check_auth_method(authtype || DEFAULT_AUTH_TYPE)
|
654
638
|
check_auth_args user, secret
|
655
639
|
end
|
656
|
-
s =
|
640
|
+
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) do
|
641
|
+
tcp_socket(@address, @port)
|
642
|
+
end
|
657
643
|
logging "Connection opened: #{@address}:#{@port}"
|
658
644
|
@socket = new_internet_message_io(tls? ? tlsconnect(s, @ssl_context_tls) : s)
|
659
645
|
check_response critical { recv_response() }
|
@@ -720,6 +706,18 @@ module Net
|
|
720
706
|
@socket = nil
|
721
707
|
end
|
722
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
|
+
|
723
721
|
#
|
724
722
|
# Message Sending
|
725
723
|
#
|
@@ -763,7 +761,9 @@ module Net
|
|
763
761
|
# * IOError
|
764
762
|
#
|
765
763
|
def send_message(msgstr, from_addr, *to_addrs)
|
764
|
+
to_addrs.flatten!
|
766
765
|
raise IOError, 'closed session' unless @socket
|
766
|
+
from_addr = Address.new(from_addr, 'SMTPUTF8') if any_require_smtputf8(to_addrs) && capable?('SMTPUTF8')
|
767
767
|
mailfrom from_addr
|
768
768
|
rcptto_list(to_addrs) {data msgstr}
|
769
769
|
end
|
@@ -816,7 +816,9 @@ module Net
|
|
816
816
|
# * IOError
|
817
817
|
#
|
818
818
|
def open_message_stream(from_addr, *to_addrs, &block) # :yield: stream
|
819
|
+
to_addrs.flatten!
|
819
820
|
raise IOError, 'closed session' unless @socket
|
821
|
+
from_addr = Address.new(from_addr, 'SMTPUTF8') if any_require_smtputf8(to_addrs) && capable?('SMTPUTF8')
|
820
822
|
mailfrom from_addr
|
821
823
|
rcptto_list(to_addrs) {data(&block)}
|
822
824
|
end
|
@@ -827,52 +829,19 @@ module Net
|
|
827
829
|
# Authentication
|
828
830
|
#
|
829
831
|
|
830
|
-
public
|
831
|
-
|
832
832
|
DEFAULT_AUTH_TYPE = :plain
|
833
833
|
|
834
834
|
def authenticate(user, secret, authtype = DEFAULT_AUTH_TYPE)
|
835
835
|
check_auth_method authtype
|
836
836
|
check_auth_args user, secret
|
837
|
-
|
838
|
-
|
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
|
837
|
+
authenticator = Authenticator.auth_class(authtype).new(self)
|
838
|
+
authenticator.auth(user, secret)
|
870
839
|
end
|
871
840
|
|
872
841
|
private
|
873
842
|
|
874
843
|
def check_auth_method(type)
|
875
|
-
unless
|
844
|
+
unless Authenticator.auth_class(type)
|
876
845
|
raise ArgumentError, "wrong authentication type #{type}"
|
877
846
|
end
|
878
847
|
end
|
@@ -890,31 +859,6 @@ module Net
|
|
890
859
|
end
|
891
860
|
end
|
892
861
|
|
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
|
916
|
-
end
|
917
|
-
|
918
862
|
#
|
919
863
|
# SMTP command dispatcher
|
920
864
|
#
|
@@ -941,29 +885,20 @@ module Net
|
|
941
885
|
|
942
886
|
# +from_addr+ is +String+ or +Net::SMTP::Address+
|
943
887
|
def mailfrom(from_addr)
|
944
|
-
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
|
945
893
|
getok((["MAIL FROM:<#{addr.address}>"] + addr.parameters).join(' '))
|
946
894
|
end
|
947
895
|
|
948
896
|
def rcptto_list(to_addrs)
|
949
897
|
raise ArgumentError, 'mail destination not given' if to_addrs.empty?
|
950
|
-
ok_users = []
|
951
|
-
unknown_users = []
|
952
898
|
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
|
899
|
+
rcptto addr
|
960
900
|
end
|
961
|
-
|
962
|
-
ret = yield
|
963
|
-
unless unknown_users.empty?
|
964
|
-
raise SMTPAuthenticationError, "failed to deliver for #{unknown_users.join(', ')}"
|
965
|
-
end
|
966
|
-
ret
|
901
|
+
yield
|
967
902
|
end
|
968
903
|
|
969
904
|
# +to_addr+ is +String+ or +Net::SMTP::Address+
|
@@ -1026,6 +961,12 @@ module Net
|
|
1026
961
|
getok('QUIT')
|
1027
962
|
end
|
1028
963
|
|
964
|
+
def get_response(reqline)
|
965
|
+
validate_line reqline
|
966
|
+
@socket.writeline reqline
|
967
|
+
recv_response()
|
968
|
+
end
|
969
|
+
|
1029
970
|
private
|
1030
971
|
|
1031
972
|
def validate_line(line)
|
@@ -1045,12 +986,6 @@ module Net
|
|
1045
986
|
res
|
1046
987
|
end
|
1047
988
|
|
1048
|
-
def get_response(reqline)
|
1049
|
-
validate_line reqline
|
1050
|
-
@socket.writeline reqline
|
1051
|
-
recv_response()
|
1052
|
-
end
|
1053
|
-
|
1054
989
|
def recv_response
|
1055
990
|
buf = ''.dup
|
1056
991
|
while true
|
@@ -1083,18 +1018,6 @@ module Net
|
|
1083
1018
|
end
|
1084
1019
|
end
|
1085
1020
|
|
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
1021
|
# This class represents a response received by the SMTP server. Instances
|
1099
1022
|
# of this class are created by the SMTP class; they should not be directly
|
1100
1023
|
# created by the user. For more information on SMTP responses, view
|
@@ -1196,17 +1119,21 @@ module Net
|
|
1196
1119
|
@parameters = address.parameters
|
1197
1120
|
else
|
1198
1121
|
@address = address
|
1199
|
-
@parameters =
|
1122
|
+
@parameters = []
|
1200
1123
|
end
|
1124
|
+
@parameters = (parameters + args + [kw_args]).map{|param| Array(param)}.flatten(1).map{|param| Array(param).compact.join('=')}.uniq
|
1201
1125
|
end
|
1202
1126
|
|
1203
1127
|
def to_s
|
1204
1128
|
@address
|
1205
1129
|
end
|
1206
1130
|
end
|
1207
|
-
|
1208
1131
|
end # class SMTP
|
1209
1132
|
|
1210
1133
|
SMTPSession = SMTP # :nodoc:
|
1134
|
+
end
|
1211
1135
|
|
1136
|
+
require_relative 'smtp/authenticator'
|
1137
|
+
Dir.glob("#{__dir__}/smtp/auth_*.rb") do |r|
|
1138
|
+
require_relative r
|
1212
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
|