uri-smtp 0.4.0 → 0.5.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: 70ec42fc77da96a4bf7e8766406f110edbbd0de008148a7b62ad64b90137515e
4
- data.tar.gz: def1342386b5d4ef7599f09750fd2dea8a709f06c452459c4f174374de4f48de
3
+ metadata.gz: 457b3741b5ef4678c7f1c6e19574f24d68d5f515ef58c6879f64516c8d472049
4
+ data.tar.gz: ecd3d5e89df1874095936cd804fd4241feefed5f2e8f6eb0f3015906d1f63cf6
5
5
  SHA512:
6
- metadata.gz: 1eeb8f2e3f8debbc08271ae35c9a55cadbd2b2d7380a86d174cfa91461012b4986e1e9489c6fde38eedf018d1e5e8601807e6ba23fb6ed1aab3d0a755d82e628
7
- data.tar.gz: d450be99efefaa24c20c2c6315a4d7b0a406d9ba043b558e6742a9bbe510670e0b6d076c5a1584ace1270ce650d73b9fd7549d93dd0853365b938b97713affe4
6
+ metadata.gz: 98b76dad4efd9c9c53f674ef06139844f8845415592bb9927ad90a7d903c62ef388a944779f55987d219035fac120e67247f50251228016db86c346e4d3bc8d3
7
+ data.tar.gz: 530215f54f3c2e1e1c78d99f476b30c11438136e1313d6abc26e7e830ee885f999c0dc90ce3e4874ac9ca11c7e45c3606a156e236ccf676bba33917b58534e18
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.0] - 2025-07-25
4
+
5
+ - Add: `uri#read_timeout`, `uri#open_timeout`
6
+ Coerced integers from query:
7
+ ```ruby
8
+ URI("smtp://foo?read_timeout=1").read_timeout #=> 1
9
+ ```
10
+ Included in `to_h`.
11
+ - Add: `uri.decoded_userinfo(format: ...)`
12
+ `:format` can be one of `[:string :array :hash]`
13
+ - Add: domain can appear in fragment
14
+ ```ruby
15
+ URI("smtp://foo.org#sender.org").domain #=> "sender.org"
16
+ ```
17
+ NOTE Any domain from the query takes precedence.
18
+ - Fix: "smtps+foo://..." having no tls
19
+
3
20
  ## [0.4.0] - 2025-07-23
4
21
 
5
22
  - FIX: correct settings for action_mailer using mail v2.8.1
@@ -11,3 +28,4 @@
11
28
  ## [0.2.0] - 2025-07-18
12
29
 
13
30
  - Feature complete
31
+
data/README.md CHANGED
@@ -1,6 +1,25 @@
1
1
  # URI::SMTP
2
2
 
3
- This library allows for parsing SMTP-URIs.
3
+ Extends Ruby's `URI` with support for SMTP-uri's.
4
+ This allows for more concise SMTP-config:
5
+ ```diff
6
+ # config/environments/production.rb
7
+ config.action_mailer.delivery_method = :smtp
8
+ - config.action_mailer.smtp_settings = {
9
+ - address: "smtp.gmail.com",
10
+ - port: 587,
11
+ - domain: "example.com",
12
+ - user_name: Rails.application.credentials.dig(:smtp, :user_name),
13
+ - password: Rails.application.credentials.dig(:smtp, :password),
14
+ - authentication: "plain",
15
+ - enable_starttls: true,
16
+ - open_timeout: 5,
17
+ - read_timeout: 5
18
+ - }
19
+ # given ENV["SMPT_URL"]:
20
+ # "smtp://user_name:password@smtp.gmail.com?open_timeout=5&read_timeout=5#example.com"
21
+ + config.action_mailer.smtp_settings = URI(ENV.fetch("SMTP_URL")).to_h(format: :am)
22
+ ```
4
23
 
5
24
  ## Installation
6
25
 
@@ -21,27 +40,29 @@ gem install uri-smtp
21
40
  ### parse
22
41
 
23
42
  ```ruby
24
- u = URI("smtps+login://user%40gmail.com:p%40ss@smtp.gmail.com?domain=sender.org")
43
+ u = URI("smtps+login://user%40gmail.com:p%40ss@smtp.gmail.com#sender.org")
25
44
 
26
45
  url.scheme #=> "smtps+login"
27
46
  url.auth #=> "login"
28
47
  url.starttls #=> false
48
+ url.starttls? #=> false
29
49
  url.tls? #=> true
30
50
  url.userinfo #=> "user%40gmail.com:p%40ss"
51
+ url.decoded_userinfo #=> ["user@gmail.com", "p@ss"]
31
52
  url.decoded_user #=> "user@gmail.com"
32
53
  url.user #=> "user%40gmail.com"
33
54
  url.decoded_password #=> "p@ss"
34
55
  url.password #=> "p%40ss"
35
56
  url.host #=> "smtp.gmail.com"
36
57
  url.port #=> 465
37
- url.domain #=> s"ender.org"
38
- url.query #=> "domain=sender.org"
58
+ url.domain #=> "sender.org"
39
59
  ```
40
60
 
41
61
  ### to_h
42
62
 
43
63
  ```ruby
44
64
  URI("smtps+login://user%40gmail.com:p%40ss@smtp.gmail.com?domain=sender.org").to_h
65
+ #=>
45
66
  {auth: "login",
46
67
  domain: "sender.org",
47
68
  host: "smtp.gmail.com",
@@ -56,6 +77,7 @@ URI("smtps+login://user%40gmail.com:p%40ss@smtp.gmail.com?domain=sender.org").to
56
77
  Formatting for action_mailer configuration, use `to_h(format: :am)`:
57
78
  ```ruby
58
79
  URI("smtps+login://user%40gmail.com:p%40ss@smtp.gmail.com?domain=sender.org").to_h(format: :am)
80
+ #=>
59
81
  {address: "smtp.gmail.com",
60
82
  authentication: "login",
61
83
  domain: "sender.org",
@@ -89,7 +111,7 @@ There's no official specification for SMTP-URIs. There's some prior work though.
89
111
  SMTP with TLS.
90
112
 
91
113
  > [!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`).
114
+ > to get `url.starttls #=> :auto`, provide it in the query: `smtp://user:pw@foo?auth=auto`. In that case `net-smtp` uses STARTTLS when the server supports it (but won't halt like when using `:always`).
93
115
 
94
116
 
95
117
  ### auth
@@ -4,6 +4,6 @@ require "uri"
4
4
 
5
5
  module URI
6
6
  class SMTP < URI::Generic
7
- VERSION = "0.4.0"
7
+ VERSION = "0.5.0"
8
8
  end
9
9
  end
data/lib/uri/smtp.rb CHANGED
@@ -21,6 +21,7 @@ module URI
21
21
  return @port if @port
22
22
  return 25 if host_local?
23
23
  return 465 if tls?
24
+
24
25
  587
25
26
  end
26
27
 
@@ -30,15 +31,56 @@ module URI
30
31
  return parsed_query["auth"] if parsed_query.has_key?("auth")
31
32
  return nil if scheme_auth == "none"
32
33
  return scheme_auth if scheme_auth
34
+
33
35
  "plain"
34
36
  end
35
37
 
38
+ # all formats: return nil when userinfo == nil.
39
+ #
40
+ # format: :array
41
+ # Never contains empty strings (as opposed to [#user, #password]).
42
+ # Example:
43
+ # Given #<URI::SMTP smtps://:token@smtp.gmail.com>
44
+ # Then:
45
+ # [uri.user, uri.password] #=> ["", "token"]
46
+ # uri.decoded_userinfo #=> [nil, "token"]
47
+ #
48
+ # format: :hash
49
+ # Keys are absent when value would be `nil`.
50
+ # Example:
51
+ # Given #<URI::SMTP smtps://:token@smtp.gmail.com>
52
+ # Then:
53
+ # uri.decoded_userinfo(format: :array) #=> [nil, "token"]
54
+ # uri.decoded_userinfo(format: :to_h) #=> {password: "token"}
55
+ def decoded_userinfo(format: :string)
56
+ return if userinfo.nil?
57
+
58
+ case format
59
+ when :string
60
+ [decoded_user, decoded_password].compact.join(":")
61
+ when :array
62
+ [string_presence(decoded_user), string_presence(decoded_password)]
63
+ when :hash
64
+ {
65
+ user: string_presence(decoded_user),
66
+ password: string_presence(decoded_password)
67
+ }.delete_if { |_k, v| v.nil? }
68
+ else
69
+ raise ArgumentError,
70
+ "Unknown format #{format.inspect}. Should be one of #{%i[string array hash].inspect}."
71
+ end
72
+ end
73
+
36
74
  def domain
37
- parsed_query["domain"]
75
+ parsed_query["domain"] || fragment
38
76
  end
39
77
 
40
- def scheme_auth
41
- scheme[/.*(?:\+(.+))/, 1]
78
+ def read_timeout
79
+ parsed_query["read_timeout"]
80
+ end
81
+
82
+ def open_timeout
83
+ parsed_query["open_timeout"]
42
84
  end
43
85
 
44
86
  def starttls
@@ -46,12 +88,13 @@ module URI
46
88
  return parsed_query["starttls"] if parsed_query.has_key?("starttls")
47
89
  return false if host_local?
48
90
  return false if insecure?
91
+
49
92
  :always
50
93
  end
51
94
  alias_method :starttls?, :starttls
52
95
 
53
96
  def tls
54
- scheme == "smtps"
97
+ !!scheme[/^smtps/]
55
98
  end
56
99
  alias_method :tls?, :tls
57
100
 
@@ -64,14 +107,18 @@ module URI
64
107
  end
65
108
 
66
109
  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
110
+ @parsed_query ||= URI.decode_www_form(query.to_s).to_h
111
+ .delete_if { |_k, v| !string_presence(v) }
112
+ .tap do
113
+ _1["read_timeout"] &&= _1["read_timeout"].to_i
114
+ _1["open_timeout"] &&= _1["open_timeout"].to_i
115
+ _1["starttls"] &&= case _1["starttls"]
116
+ when "always", "auto" then _1["starttls"].to_sym
117
+ when "false" then false
118
+ else
119
+ :always
120
+ end
73
121
  end
74
- end
75
122
  end
76
123
 
77
124
  def to_h(format: nil)
@@ -83,7 +130,9 @@ module URI
83
130
  domain:,
84
131
  enable_starttls: starttls == :always,
85
132
  enable_starttls_auto: starttls == :auto,
133
+ open_timeout:,
86
134
  port:,
135
+ read_timeout:,
87
136
  tls:
88
137
  }.tap do
89
138
  unless _1[:authentication].nil?
@@ -104,7 +153,9 @@ module URI
104
153
  auth:,
105
154
  domain:,
106
155
  host:,
156
+ open_timeout:,
107
157
  port:,
158
+ read_timeout:,
108
159
  scheme:,
109
160
  starttls:,
110
161
  tls:
@@ -120,6 +171,16 @@ module URI
120
171
  def self.parse(uri)
121
172
  new(*URI.split(uri))
122
173
  end
174
+
175
+ private
176
+
177
+ def scheme_auth
178
+ scheme[/.*(?:\+(.+))/, 1]
179
+ end
180
+
181
+ def string_presence(s)
182
+ s.to_s.strip.then { _1 unless _1.empty? }
183
+ end
123
184
  end
124
185
 
125
186
  register_scheme "SMTP", SMTP
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.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gert Goet