uri-smtp 0.1.0 → 0.3.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/CHANGELOG.md +6 -2
- data/README.md +115 -1
- data/lib/uri/smtp/version.rb +1 -1
- data/lib/uri/smtp.rb +116 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 534a3148493353560954ff1399ed0bcc5972fb84a0a72f95389827e9b2e59c66
|
4
|
+
data.tar.gz: 0701b94ea526034678a4cd2cdd72996ca3e21e8e2a91d1ce4ea120a4ccc09c7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59430a383a5a47c243dfe487d51f5749c0a58ffd1ba836c6fe1fb53c3b51927fed39329ba83f5a7853456a0f48abe13e7402cf33d182c6ed7d9881c53606366b
|
7
|
+
data.tar.gz: ab4b650b59960e5d6b1859ec78ea266fa1b50b4cc3d01c592662be8f3562bfc40a7ca70e4296a7b5a4fba9e1df5f6797b79851236223c9fcfec23d5f409d2345
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# URI::SMTP
|
2
2
|
|
3
|
-
|
3
|
+
This library allows for parsing SMTP-URIs.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,6 +18,120 @@ gem install uri-smtp
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
+
### parse
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
u = URI("smtps+login://user%40gmail.com:p%40ss@smtp.gmail.com?domain=sender.org")
|
25
|
+
|
26
|
+
url.scheme #=> "smtps+login"
|
27
|
+
url.auth #=> "login"
|
28
|
+
url.starttls #=> false
|
29
|
+
url.tls? #=> true
|
30
|
+
url.userinfo #=> "user%40gmail.com:p%40ss"
|
31
|
+
url.decoded_user #=> "user@gmail.com"
|
32
|
+
url.user #=> "user%40gmail.com"
|
33
|
+
url.decoded_password #=> "p@ss"
|
34
|
+
url.password #=> "p%40ss"
|
35
|
+
url.host #=> "smtp.gmail.com"
|
36
|
+
url.port #=> 465
|
37
|
+
url.domain #=> s"ender.org"
|
38
|
+
url.query #=> "domain=sender.org"
|
39
|
+
```
|
40
|
+
|
41
|
+
### to_h
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
URI("smtps+login://user%40gmail.com:p%40ss@smtp.gmail.com?domain=sender.org").to_h
|
45
|
+
{auth: "login",
|
46
|
+
domain: "sender.org",
|
47
|
+
host: "smtp.gmail.com",
|
48
|
+
port: 587,
|
49
|
+
scheme: "smtps+login",
|
50
|
+
starttls: :always,
|
51
|
+
tls: false,
|
52
|
+
user: "user@gmail.com",
|
53
|
+
password: "p@ss"}
|
54
|
+
```
|
55
|
+
|
56
|
+
Formatting for action_mailer configuration, use `to_h(format: :am)`:
|
57
|
+
```ruby
|
58
|
+
URI("smtps+login://user%40gmail.com:p%40ss@smtp.gmail.com?domain=sender.org").to_h(format: :am)
|
59
|
+
{address: "smtp.gmail.com",
|
60
|
+
authentication: "login",
|
61
|
+
domain: "sender.org",
|
62
|
+
enable_starttls: :always,
|
63
|
+
port: 587,
|
64
|
+
user_name: "user@gmail.com",
|
65
|
+
password: "p@ss"}
|
66
|
+
```
|
67
|
+
|
68
|
+
|
69
|
+
Full Rails config:
|
70
|
+
```ruby
|
71
|
+
config.action_mailer.delivery_method = :smtp
|
72
|
+
# [mailcatcher](https://github.com/sj26/mailcatcher) fallback:
|
73
|
+
config.action_mailer.smtp_settings = URI(ENV.fetch("SMTP_URL", "smtp://127.0.0.1:1025")).to_h(format: :am)
|
74
|
+
```
|
75
|
+
|
76
|
+
## SMTP-URI
|
77
|
+
|
78
|
+
There's no official specification for SMTP-URIs. There's some prior work though. This implementation is heavily inspired by [aerc](https://git.sr.ht/~rjarry/aerc/tree/master/item/doc/aerc-smtp.5.scd).
|
79
|
+
|
80
|
+
`<scheme>[+<auth>]://[<user>[:<password>]@]<host>[:<port>][?<query>][#<fragment>]`
|
81
|
+
|
82
|
+
### scheme
|
83
|
+
|
84
|
+
- `smtp`
|
85
|
+
SMTP with STARTTLS (i.e. `url.starttls #=> :always`).
|
86
|
+
- `smtp+insecure`
|
87
|
+
SMTP without STARTTLS (i.e. `url.starttls #=> false`)..
|
88
|
+
- `smtps`
|
89
|
+
SMTP with TLS.
|
90
|
+
|
91
|
+
> [!NOTE]
|
92
|
+
> to get `url.starttls #=> :auto`, provide it in the query: `smtp://foo?auth=auto`. In that case `net-smtp` uses STARTTLS when the server supports it (but won't halt like when using `:always`).
|
93
|
+
|
94
|
+
|
95
|
+
### auth
|
96
|
+
|
97
|
+
There's no restriction to the value of auth. Though the following values have special meaning:
|
98
|
+
|
99
|
+
- `none`
|
100
|
+
No authentication is required.
|
101
|
+
- `plain`
|
102
|
+
Authenticate with a username and password using AUTH PLAIN. This is the default behavior.
|
103
|
+
|
104
|
+
> [!NOTE]
|
105
|
+
> any query's value for `auth` takes precedence.
|
106
|
+
|
107
|
+
### Examples
|
108
|
+
|
109
|
+
| SMTP URI | TLS? | Port | STARTTLS | Auth Method | Notes |
|
110
|
+
|----------|---------|------|----------|-------------|-------|
|
111
|
+
| `smtp://smtp.example.com` | ❌ | 587 | ⚡ | none | Standard submission with STARTTLS `:always` |
|
112
|
+
| `smtp+insecure://smtp.example.com` | ❌ | 587 | ❌ | none | Standard submission without STARTTLS |
|
113
|
+
| `smtp+insecure+login://user:pass@smtp.example.com` | ❌ | 587 | ❌ | login | Authenticate insecurely using LOGIN auth |
|
114
|
+
| `smtp://smtp.example.com?starttls=auto` | ❌ | 587 | 🔄 | none | Standard submission with STARTTLS `:auto` |
|
115
|
+
| `smtp://smtp.example.com:1025` | ❌ | 1025 | ⚡ | none | Standard submission with STARTTLS `:always` on custom port |
|
116
|
+
| `smtp://user:pass@mail.example.com` | ❌ | 587 | ⚡ | plain | STARTTLS `:always` with (default) PLAIN auth |
|
117
|
+
| `smtp+login://user:pass@mail.example.com` | ❌ | 587 | ⚡ | login | STARTTLS `:always` with LOGIN auth |
|
118
|
+
| `smtp+none://mail.example.com` | ❌ | 587 | 🔄 | none | Explicit no authentication |
|
119
|
+
| `smtps://mail.example.com` | ✅ | 465 | ❌ | none | Direct TLS connection |
|
120
|
+
| `smtps://mail.example.com?domain=sender.org&read_timeout=5&open_timeout=5` | ✅ | 465 | ❌ | none | `domain`, `read_timeout` and `open_timeout` set |
|
121
|
+
| `smtps+login://user@imap.gmail.com` | ✅ | 465 | ❌ | login | Direct TLS with LOGIN auth |
|
122
|
+
| `smtps://user%40gmail.com:p%40ss@imap.gmail.com` | ✅ | 465 | ❌ | login | Direct TLS with encoded userinfo `user@gmail.com:p@ss` |
|
123
|
+
| `smtp://localhost` | ❌ | 25 | ❌ | none | Local delivery (no encryption) |
|
124
|
+
| `smtp://127.0.0.1` | ❌ | 25 | ❌ | none | Local delivery (no encryption) |
|
125
|
+
|
126
|
+
**Legend**
|
127
|
+
|
128
|
+
`STARTTLS`
|
129
|
+
- ⚡ = `:always`
|
130
|
+
Require STARTTLS (i.e. `net-smtp` aborts when server doesn't support STARTTLS).
|
131
|
+
- 🔄 = `:auto`
|
132
|
+
Use STARTTLS if supported by server.
|
133
|
+
- ❌ = `false`
|
134
|
+
No STARTTLS. This is always the case when using TLS.
|
21
135
|
|
22
136
|
## Development
|
23
137
|
|
data/lib/uri/smtp/version.rb
CHANGED
data/lib/uri/smtp.rb
CHANGED
@@ -6,8 +6,124 @@ require_relative "smtp/version"
|
|
6
6
|
module URI
|
7
7
|
class SMTP < URI::Generic
|
8
8
|
class Error < StandardError; end
|
9
|
+
|
10
|
+
def initialize(scheme,
|
11
|
+
userinfo, host, port, registry,
|
12
|
+
path, opaque,
|
13
|
+
query,
|
14
|
+
fragment,
|
15
|
+
parser = DEFAULT_PARSER,
|
16
|
+
arg_check = false)
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def port
|
21
|
+
return @port if @port
|
22
|
+
return 25 if host_local?
|
23
|
+
return 465 if tls?
|
24
|
+
587
|
25
|
+
end
|
26
|
+
|
27
|
+
def auth
|
28
|
+
# net-smtp: passing authtype without user/pw raises error
|
29
|
+
return nil unless userinfo
|
30
|
+
return parsed_query["auth"] if parsed_query.has_key?("auth")
|
31
|
+
return nil if scheme_auth == "none"
|
32
|
+
return scheme_auth if scheme_auth
|
33
|
+
"plain"
|
34
|
+
end
|
35
|
+
|
36
|
+
def domain
|
37
|
+
parsed_query["domain"]
|
38
|
+
end
|
39
|
+
|
40
|
+
def scheme_auth
|
41
|
+
scheme[/.*(?:\+(.+))/, 1]
|
42
|
+
end
|
43
|
+
|
44
|
+
def starttls
|
45
|
+
return false if tls?
|
46
|
+
return parsed_query["starttls"] if parsed_query.has_key?("starttls")
|
47
|
+
return false if host_local?
|
48
|
+
return false if insecure?
|
49
|
+
:always
|
50
|
+
end
|
51
|
+
alias_method :starttls?, :starttls
|
52
|
+
|
53
|
+
def tls
|
54
|
+
scheme == "smtps"
|
55
|
+
end
|
56
|
+
alias_method :tls?, :tls
|
57
|
+
|
58
|
+
def insecure?
|
59
|
+
scheme == "smtp+insecure"
|
60
|
+
end
|
61
|
+
|
62
|
+
def host_local?
|
63
|
+
%w[127.0.0.1 localhost].include?(host)
|
64
|
+
end
|
65
|
+
|
66
|
+
def parsed_query
|
67
|
+
@parsed_query ||= URI.decode_www_form(query.to_s).to_h.tap do
|
68
|
+
_1["starttls"] &&= case _1["starttls"]
|
69
|
+
when "always", "auto" then _1["starttls"].to_sym
|
70
|
+
when "false" then false
|
71
|
+
else
|
72
|
+
:always
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_h(format: nil)
|
78
|
+
case format
|
79
|
+
when :am, :action_mailer
|
80
|
+
{
|
81
|
+
address: host,
|
82
|
+
authentication: auth,
|
83
|
+
domain:,
|
84
|
+
enable_starttls: starttls,
|
85
|
+
port:
|
86
|
+
}.tap do
|
87
|
+
unless _1[:authentication].nil?
|
88
|
+
_1[:user_name] = decoded_user
|
89
|
+
_1[:password] = decoded_password
|
90
|
+
end
|
91
|
+
end.delete_if { |_k, v| v.nil? }
|
92
|
+
else
|
93
|
+
{
|
94
|
+
auth:,
|
95
|
+
domain:,
|
96
|
+
host:,
|
97
|
+
port:,
|
98
|
+
scheme:,
|
99
|
+
starttls:,
|
100
|
+
tls:
|
101
|
+
}.tap do
|
102
|
+
unless _1[:auth].nil?
|
103
|
+
_1[:user] = decoded_user
|
104
|
+
_1[:password] = decoded_password
|
105
|
+
end
|
106
|
+
end.delete_if { |_k, v| v.nil? }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.parse(uri)
|
111
|
+
new(*URI.split(uri))
|
112
|
+
end
|
9
113
|
end
|
10
114
|
|
11
115
|
register_scheme "SMTP", SMTP
|
12
116
|
register_scheme "SMTPS", SMTP
|
13
117
|
end
|
118
|
+
|
119
|
+
module UriSmtpExtensions
|
120
|
+
def parse(uri)
|
121
|
+
if uri.is_a?(String) && uri.start_with?("smtp")
|
122
|
+
return URI::SMTP.parse(uri)
|
123
|
+
end
|
124
|
+
|
125
|
+
super
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
URI.singleton_class.prepend(UriSmtpExtensions)
|