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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a8bf2f07b31cf5111ff58301d72dd91f186b890d417e0c22ab8d353c541ea763
4
- data.tar.gz: e4b9f677a881051408f03e11a90a01095269c533cfc6cb34972c10fa358390b1
3
+ metadata.gz: 534a3148493353560954ff1399ed0bcc5972fb84a0a72f95389827e9b2e59c66
4
+ data.tar.gz: 0701b94ea526034678a4cd2cdd72996ca3e21e8e2a91d1ce4ea120a4ccc09c7b
5
5
  SHA512:
6
- metadata.gz: 020ece2e1fc267c79ac9a28b5d74f57e448696676419c5eb6393e9db3f96a39abc7c1a11555000b793ae659013d2e8634bbdcd1d97199589a50704cdf51516d3
7
- data.tar.gz: 7bcfcd9a669f90c42abe78f5a96c0af16ba4593ade3d42c3b90b43f8d8a620a464c96e4e836d4f8a4424bb08ac0c30ca0a1ffc88ee57ed49d761e809bfc9f7fd
6
+ metadata.gz: 59430a383a5a47c243dfe487d51f5749c0a58ffd1ba836c6fe1fb53c3b51927fed39329ba83f5a7853456a0f48abe13e7402cf33d182c6ed7d9881c53606366b
7
+ data.tar.gz: ab4b650b59960e5d6b1859ec78ea266fa1b50b4cc3d01c592662be8f3562bfc40a7ca70e4296a7b5a4fba9e1df5f6797b79851236223c9fcfec23d5f409d2345
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2025-07-15
3
+ ## [0.3.0] - 2025-07-23
4
4
 
5
- - Initial release
5
+ - FIX: Kernel.URI should accept URI's
6
+
7
+ ## [0.2.0] - 2025-07-18
8
+
9
+ - Feature complete
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # URI::SMTP
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/uri/smtp`. To experiment with that code, run `bin/console` for an interactive prompt.
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
 
@@ -4,6 +4,6 @@ require "uri"
4
4
 
5
5
  module URI
6
6
  class SMTP < URI::Generic
7
- VERSION = "0.1.0"
7
+ VERSION = "0.3.0"
8
8
  end
9
9
  end
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)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uri-smtp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gert Goet