midi-smtp-server 3.0.3 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a57da18e0a784683fa297898113f75967fb3adb852270e22b733f7b8bd29e7d0
4
- data.tar.gz: 95d9bdb5940ddcd8d49fbf3dd0f7b8f023235d58de00ee1c49be0aeb97da3101
3
+ metadata.gz: 2376ca7f3510ebe230523b2fd5629dc39a5c44f3415ce3980d1e27d156ac3397
4
+ data.tar.gz: eaeb5ae1fe8dd868b772d9dfa267665e2b0e8b6f63c4761cab2d861cac412499
5
5
  SHA512:
6
- metadata.gz: 37260846efd563b0b66ecf25e50b61b521c21a653a100cac2b2bceb8d40ed02c622b056f2e7835715568fe82317e5527148a67da4ba7d2cb840c84dda655ca45
7
- data.tar.gz: bc79e07e38642e758b3658a2776afcd9605d75e8061d77c5dd4ea21829330ac02e65c1db07faf45a7916f00996dcba2799842ec2e1aafdb1eea3518dcff7ffed
6
+ metadata.gz: da5d3c16c081cd3c34be74d1f745bcc015e5c1fa9bbcdf6d55552e1e2c30df831ad63c025c86e4ffda078dc37b1c7bcf16d14fe512dbb91bbabb54dd9b2ca944
7
+ data.tar.gz: acbdac6c519f20758e9af7922094032ce3d3bc67e4874d8b37bac283e408ca303cd3fc47ae51b360e3ef9d1bfddc68bc620f5a105e4a68ca4a3d0ca3fef73ef6
data/CHANGELOG.md CHANGED
@@ -4,9 +4,30 @@ We suggest everybody using MidiSmtpServer to switch at least to latest 2.3.y. or
4
4
 
5
5
  For upgrades from previous versions or outdated _MiniSmtpServer_ gem you may follow the guides at [Appendix Upgrade](https://midi-smtp-server.readthedocs.io/appendix_upgrade/) to get your code ready for the latest releases.
6
6
 
7
+
8
+ #### 3.2.1 (2023-08-15)
9
+
10
+ 1. New feature [proxy](https://midi-smtp-server.readthedocs.io/feature_proxy) ([check issue 49](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/49))
11
+ 2. mkdocs update for readthedocs
12
+
13
+
14
+ #### 3.1.2 (2023-05-06)
15
+
16
+ 1. Minor fix for backwards compatibility to method `start` when not using pre_fork options.
17
+
18
+
19
+ #### 3.1.1 (2023-02-26)
20
+
21
+ 1. Add option to additional activate [pre-forking workers](https://midi-smtp-server.readthedocs.io/feature_load_balancing/#pre-forking) (beta) ([check issue 42](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/42))
22
+ 2. Adjust sleep idle time while in command and data loop to speedup processing ([check issue 47](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/47))
23
+ 3. Mark the current default value `0.1` for `io_waitreadable_sleep` as deprecated, will become `0.03` in a future version.
24
+ 4. Modify github workflow and apply testing of ruby 3.1 and ruby 3.2
25
+ 5. Generate updated openssl test certificates for TLS tests
26
+
27
+
7
28
  #### 3.0.3 (2022-02-12)
8
29
 
9
- 1. Critical fix for thread safety ([check issue 29](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/39))
30
+ 1. Critical fix for thread safety ([check issue 39](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/39))
10
31
  2. Fix tests using net/smtp '>= 0.3.1'
11
32
 
12
33
 
@@ -29,14 +50,13 @@ For upgrades from previous versions or outdated _MiniSmtpServer_ gem you may fol
29
50
  10. Dropped deprecated empty wildcard `""` support on initialize - please use specific hostnames and / or ip-addresses or star wildcard `"*"` only
30
51
  11. Align tests with Rubocop style and coding enforcements
31
52
  12. Added `rake` tasks for testing and linting, checkout `bundle exec rake -T`
32
- 13. Re-defined arguments of methods `new`, `join`, `stop` as keyword arguments, check [minor incompatability: upgrade to 3.x](https://midi-smtp-server.readthedocs.io/appendix_upgrade/#upgrade-to-3x)
53
+ 13. Re-defined arguments of methods `new`, `join`, `stop` as keyword arguments, check [minor incompatibility: upgrade to 3.x](https://midi-smtp-server.readthedocs.io/appendix_upgrade/#upgrade-to-3x)
33
54
  14. Enhance the slack recipe in cookbook for [Docker usage](https://github.com/4commerce-technologies-AG/midi-smtp-server/tree/master/cookbook/recipe-slack)
34
55
 
35
56
 
36
57
  #### 2.3.3 (2022-02-12)
37
58
 
38
- 1. Critical fix for thread safety ([check issue 29](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/39))
39
- 2. Fix tests using net/smtp '>= 0.3.1'
59
+ 1. Critical fix for thread safety ([check issue 39](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/39))
40
60
 
41
61
 
42
62
  #### 2.3.2 (2020-01-21)
@@ -61,7 +81,7 @@ For upgrades from previous versions or outdated _MiniSmtpServer_ gem you may fol
61
81
 
62
82
  1. Support [IPv4 and IPv6 (documentation)](https://midi-smtp-server.readthedocs.io/instantiate/#ipv4-and-ipv6-ready)
63
83
  2. Support binding of [multiple ports and hosts / ip addresses](https://midi-smtp-server.readthedocs.io/instantiate/#ports-and-addresses)
64
- 3. Handle [utilization of connections and processings](https://midi-smtp-server.readthedocs.io/feature_utilization/)
84
+ 3. Handle [utilization of connections and processings](https://midi-smtp-server.readthedocs.io/feature_load_balancing/)
65
85
  4. Support of RFC(2)822 [CR LF modes](https://midi-smtp-server.readthedocs.io/feature_cr_lf_modes/)
66
86
  5. Support (optionally) SMTP [PIPELINING](https://tools.ietf.org/html/rfc2920) extension
67
87
  6. Support (optionally) SMTP [8BITMIME](https://midi-smtp-server.readthedocs.io/feature_8bitmime_smtputf8/) extension
@@ -104,7 +124,7 @@ For upgrades from previous versions or outdated _MiniSmtpServer_ gem you may fol
104
124
 
105
125
  #### 2.x
106
126
 
107
- 1. Modulized
127
+ 1. Modularized
108
128
  2. Removed dependency to GServer
109
129
  3. Additional events to interact with
110
130
  4. Use logger to log several messages from severity :debug up to :fatal
data/MIT-LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014 - 2022 Tom Freudenberg
3
+ Copyright (c) 2014 - 2023 Tom Freudenberg
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -19,7 +19,7 @@ MidiSmtpServer is the highly customizable ruby SMTP-Server and SMTP-Service libr
19
19
 
20
20
  As a library it is mainly designed to be integrated into your projects as serving a SMTP-Server service. The lib will do nothing with your mail and you have to create your own event functions to handle and operate on incoming mails. We are using this in conjunction with [Mikel Lindsaar](https://github.com/mikel) great Mail component (https://github.com/mikel/mail). Time to run your own SMTP-Server service.
21
21
 
22
- Checkout all the features and improvements (3.0.1 Logging enhancement, 2.3.x Multiple ports and addresses, 2.2.x Encryption [StartTLS], 2.1.0 Authentication [AUTH], 2.1.1 significant speed improvement, etc.) and get more details from section [changes and updates](https://github.com/4commerce-technologies-AG/midi-smtp-server#changes-and-updates).
22
+ Checkout all the features and improvements (3.1.1 Process parallelization, 3.0.1 Logging enhancement, 2.3.x Multiple ports and addresses, 2.2.x Encryption [StartTLS], 2.1.0 Authentication [AUTH], 2.1.1 significant speed improvement, etc.) and get more details from section [changes and updates](https://github.com/4commerce-technologies-AG/midi-smtp-server#changes-and-updates).
23
23
 
24
24
  MidiSmtpServer is an extremely flexible library and almost any aspect of SMTP communications can be handled by deriving its events and using its configuration options.
25
25
 
@@ -40,10 +40,10 @@ class MySmtpd < MidiSmtpServer::Smtpd
40
40
  logger.debug("[#{ctx[:envelope][:from]}] for recipient(s): [#{ctx[:envelope][:to]}]...")
41
41
 
42
42
  # Just decode message once to make sure, that this message ist readable
43
- @mail = Mail.read_from_string(ctx[:message][:data])
43
+ mail = Mail.read_from_string(ctx[:message][:data])
44
44
 
45
45
  # handle incoming mail, just show the message subject
46
- logger.debug(@mail.subject)
46
+ logger.debug(mail.subject)
47
47
  end
48
48
 
49
49
  end
@@ -64,10 +64,10 @@ This source code shows the example to receive messages via SMTP and store them t
64
64
  # get each message after DATA <message> .
65
65
  def on_message_data_event(ctx)
66
66
  # Just decode message once to make sure, that this message ist readable
67
- @mail = Mail.read_from_string(ctx[:message])
67
+ mail = Mail.read_from_string(ctx[:message])
68
68
 
69
69
  # Publish to rabbit
70
- @bunny_exchange.publish(@mail.to_s, :headers => { 'x-smtp' => @mail.header.to_s }, :routing_key => "to_queue")
70
+ @bunny_exchange.publish(mail.to_s, :headers => { 'x-smtp' => mail.header.to_s }, :routing_key => "to_queue")
71
71
  end
72
72
  ```
73
73
 
@@ -76,7 +76,11 @@ This source code shows the example to receive messages via SMTP and store them t
76
76
 
77
77
  ## Installation
78
78
 
79
- MidiSmtpServer is packaged as a RubyGem so that you can easily install by entering following at your command line:
79
+ MidiSmtpServer is packaged as a RubyGem and hosted on rubygems.
80
+
81
+ #### CLI
82
+
83
+ You can easily install the package by entering following at your command line:
80
84
 
81
85
  `gem install midi-smtp-server`
82
86
 
@@ -84,6 +88,14 @@ Use the component in your project sources by:
84
88
 
85
89
  `require 'midi-smtp-server'`
86
90
 
91
+ #### Gemfile
92
+
93
+ When a `Gemfile` handles your dependencies, please consider to use the [pessimistic operator](https://thoughtbot.com/blog/rubys-pessimistic-operator) at least:
94
+
95
+ `gem 'midi-smtp-server', '~> 3.1.2''`
96
+
97
+ All changes by PATCH versions are always functional and compatible with no issues on update!
98
+
87
99
  <br>
88
100
 
89
101
 
@@ -96,35 +108,35 @@ Read the [MidiSmtpServer Documentation](https://midi-smtp-server.readthedocs.io/
96
108
 
97
109
  ## Reliable code
98
110
 
99
- Since version 2.3 implementation and integration tests by minitest framework are added to this repository. While the implementation tests are mostly checking the components, the integration tests try to verify the correct exchange of messages for different scenarios. In addtion all sources are checked by rubocop to ensure they fit to the style guides.
111
+ Since version 2.3 implementation and integration tests by minitest framework are added to this repository. While the implementation tests are mostly checking the components, the integration tests try to verify the correct exchange of messages for different scenarios. Last but not least the stress tests do catch some rare conditions to make sure that no information is leaving its thread and process. In addition all sources are checked by rubocop to ensure they fit to the style guides.
100
112
 
101
113
  You may run all rubocop tests through the `rake` helper:
102
114
 
103
- ``` bash
115
+ ```bash
104
116
  bundle exec rake rubocop
105
117
  ```
106
118
 
107
119
  You may also run all tests through the `rake` helper:
108
120
 
109
- ``` bash
121
+ ```bash
110
122
  bundle exec rake test:all
111
123
  ```
112
124
 
113
125
  or with more verbose output:
114
126
 
115
- ``` bash
127
+ ```bash
116
128
  bundle exec rake test:all v=1
117
129
  ```
118
130
 
119
- To just run just a part of the tests, you may select the `specs`, `unit` or `integration` tests:
131
+ To just run just a part of the tests, you may select the `specs`, `unit`, `integration` or `stress` tests:
120
132
 
121
- ``` bash
133
+ ```bash
122
134
  bundle exec rake test:specs
123
135
  ```
124
136
 
125
137
  To just run some selected (by regular expression) tests, you may use the `T=filter` option. The example will run only the tests and specs containing the word _connections_ in their method_name or describe_text:
126
138
 
127
- ``` bash
139
+ ```bash
128
140
  bundle exec rake test:all v=1 T=connections
129
141
  ```
130
142
 
@@ -146,10 +158,11 @@ We suggest everybody using MidiSmtpServer to switch at least to latest 2.3.y. or
146
158
 
147
159
  For upgrades from previous versions or outdated _MiniSmtpServer_ gem you may follow the guides (see appendix) how to change your existing code to be compatible with the latest releases.
148
160
 
149
- #### Latest release: 3.0.3 (2022-02-12)
150
161
 
151
- 1. Critical fix for thread safety ([check issue 29](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/39))
152
- 2. Fix tests using net/smtp '>= 0.3.1'
162
+ #### Latest release: 3.2.1 (2023-08-15)
163
+
164
+ 1. New feature [proxy](https://midi-smtp-server.readthedocs.io/feature_proxy) ([check issue 49](https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/49))
165
+ 2. mkdocs update for readthedocs
153
166
 
154
167
 
155
168
  #### Changelog history
@@ -171,6 +184,7 @@ Checkout the [Appendix Upgrade](https://midi-smtp-server.readthedocs.io/appendix
171
184
  You may find, use and download the gem package on [RubyGems.org](http://rubygems.org/gems/midi-smtp-server).
172
185
 
173
186
  [![Gem Version](https://badge.fury.io/rb/midi-smtp-server.svg)](http://badge.fury.io/rb/midi-smtp-server) &nbsp;
187
+ [![Ruby](https://github.com/4commerce-technologies-AG/midi-smtp-server/actions/workflows/push-and-pr-testing-ruby-ci.yml/badge.svg)](https://github.com/4commerce-technologies-AG/midi-smtp-server/actions/workflows/push-and-pr-testing-ruby-ci.yml) &nbsp;
174
188
 
175
189
  <br>
176
190
 
@@ -189,6 +203,6 @@ You may find, use and download the gem package on [RubyGems.org](http://rubygems
189
203
 
190
204
  Author: [Tom Freudenberg](http://about.me/tom.freudenberg)
191
205
 
192
- [MidiSmtpServer Class](https://github.com/4commerce-technologies-AG/midi-smtp-server/) is inspired from [MiniSmtpServer Class](https://github.com/aarongough/mini-smtp-server) and code written by [Aaron Gough](https://github.com/aarongough) and [Peter Cooper](http://peterc.org/)
206
+ [MidiSmtpServer Class](https://github.com/4commerce-technologies-AG/midi-smtp-server/) is inspired from [MiniSmtpServer Class](https://github.com/aarongough/mini-smtp-server) and code written by [Aaron Gough](https://github.com/aarongough) and [Peter Cooper](https://github.com/4commerce-technologies-AG/midi-smtp-server#author--credits)
193
207
 
194
- Copyright (c) 2014-2022 [Tom Freudenberg](http://www.4commerce.de/), [4commerce technologies AG](http://www.4commerce.de/), released under the MIT license
208
+ Copyright (c) 2014-2023 [Tom Freudenberg](https://github.com/TomFreudenberg), [4commerce technologies AG](https://www.4commerce.de/), released under the MIT license
@@ -10,7 +10,7 @@ module MidiSmtpServer
10
10
  class SmtpdIOTimeoutException < RuntimeError
11
11
  end
12
12
 
13
- # special internal exception to signal buffer size exceedance
13
+ # special internal exception to signal buffer size exceeding
14
14
  # while waiting for incoming data line
15
15
  class SmtpdIOBufferOverrunException < RuntimeError
16
16
  end
@@ -286,7 +286,7 @@ module MidiSmtpServer
286
286
 
287
287
  end
288
288
 
289
- # Status when expeting CRLF sequence as line breaks (RFC(2)822)
289
+ # Status when expecting CRLF sequence as line breaks (RFC(2)822)
290
290
 
291
291
  # 500 Bad input, missing CRLF line termination
292
292
  class Smtpd500CrLfSequenceException < SmtpdException
@@ -69,9 +69,9 @@ module MidiSmtpServer
69
69
  @ssl_context.cert.sign @ssl_context.key, OpenSSL::Digest.new('SHA256')
70
70
  logger.debug("SSL: generated test certificate\r\n#{@ssl_context.cert.to_text}")
71
71
  else
72
- # if any is set, test the pathes
73
- raise "File \”#{@cert_path}\" does not exist or is not a regular file. Could not load certificate." unless File.file?(@cert_path.to_s)
74
- raise "File \”#{@key_path}\" does not exist or is not a regular file. Could not load private key." unless @key_path.nil? || File.file?(@key_path.to_s)
72
+ # if any is set, test the paths
73
+ raise "File \"#{@cert_path}\" does not exist or is not a regular file. Could not load certificate." unless File.file?(@cert_path.to_s)
74
+ raise "File \"#{@key_path}\" does not exist or is not a regular file. Could not load private key." unless @key_path.nil? || File.file?(@key_path.to_s)
75
75
  # try to load certificate and key
76
76
  cert_lines = File.read(@cert_path.to_s).lines
77
77
  # check if the cert file contains a chain of certs
@@ -6,12 +6,12 @@ module MidiSmtpServer
6
6
  module VERSION
7
7
 
8
8
  MAJOR = 3
9
- MINOR = 0
10
- TINY = 3
9
+ MINOR = 2
10
+ TINY = 1
11
11
 
12
12
  STRING = [MAJOR, MINOR, TINY].compact.join('.')
13
13
 
14
- DATE = '2022-02-12'
14
+ DATE = '2023-08-15'
15
15
 
16
16
  end
17
17
 
@@ -17,24 +17,27 @@ module MidiSmtpServer
17
17
  # default values
18
18
  DEFAULT_SMTPD_HOST = '127.0.0.1'
19
19
  DEFAULT_SMTPD_PORT = 2525
20
+ DEFAULT_SMTPD_PRE_FORK = 0
20
21
  DEFAULT_SMTPD_MAX_PROCESSINGS = 4
21
22
 
22
- # default values for conformity to RFC(2)822 and addtionals
23
+ # default values for conformity to RFC(2)822 and additional
23
24
  # if interested in details, checkout discussion on issue queue at:
24
25
  # https://github.com/4commerce-technologies-AG/midi-smtp-server/issues/16
25
26
  CRLF_MODES = [:CRLF_ENSURE, :CRLF_LEAVE, :CRLF_STRICT].freeze
26
27
  DEFAULT_CRLF_MODE = :CRLF_ENSURE
27
28
 
28
29
  # default values for IO operations
30
+ DEFAULT_IO_WAITREADABLE_SLEEP = 0.1
29
31
  DEFAULT_IO_CMD_TIMEOUT = 30
30
32
  DEFAULT_IO_BUFFER_CHUNK_SIZE = 4 * 1024
31
33
  DEFAULT_IO_BUFFER_MAX_SIZE = 1 * 1024 * 1024
32
34
 
33
35
  # default value for SMTPD extensions support
36
+ DEFAULT_PROXY_EXTENSION_ENABLED = false
34
37
  DEFAULT_PIPELINING_EXTENSION_ENABLED = false
35
38
  DEFAULT_INTERNATIONALIZATION_EXTENSIONS_ENABLED = false
36
39
 
37
- # Authentification modes
40
+ # Authentication modes
38
41
  AUTH_MODES = [:AUTH_FORBIDDEN, :AUTH_OPTIONAL, :AUTH_REQUIRED].freeze
39
42
  DEFAULT_AUTH_MODE = :AUTH_FORBIDDEN
40
43
 
@@ -43,31 +46,42 @@ module MidiSmtpServer
43
46
 
44
47
  public
45
48
 
46
- # Start the server
49
+ # Create the server
47
50
  def start
48
- serve_service
51
+ create_service
52
+ # immediately attach the threads to running single master process (default)
53
+ attach_threads unless pre_fork?
49
54
  end
50
55
 
51
56
  # Stop the server
52
57
  def stop(wait_seconds_before_close: 2, gracefully: true)
53
- # always signal shutdown
54
- shutdown if gracefully
55
- # wait if some connection(s) need(s) more time to handle shutdown
56
- sleep wait_seconds_before_close if connections?
57
- # drop tcp_servers while raising SmtpdStopServiceException
58
- @connections_mutex.synchronize do
59
- @tcp_server_threads.each do |tcp_server_thread|
60
- # use safe navigation (&.) to make sure that obj exists like ... if tcp_server_thread
61
- tcp_server_thread&.raise SmtpdStopServiceException
58
+ begin
59
+ # signal pre_forked workers to stop
60
+ @workers.each { |worker_pid| Process.kill(:TERM, worker_pid) } if pre_fork? && master?
61
+ # always signal shutdown
62
+ shutdown if gracefully
63
+ # wait if some connection(s) need(s) more time to handle shutdown
64
+ sleep wait_seconds_before_close if connections?
65
+ # drop tcp_servers while raising SmtpdStopServiceException
66
+ @connections_mutex.synchronize do
67
+ @tcp_server_threads.each do |tcp_server_thread|
68
+ # use safe navigation (&.) to make sure that obj exists like ... if tcp_server_thread
69
+ tcp_server_thread&.raise SmtpdStopServiceException
70
+ end
62
71
  end
72
+
73
+ ensure
74
+ # check for removing TCPServers
75
+ @tcp_servers.each { |tcp_server| remove_tcp_server(tcp_server) } if master?
63
76
  end
77
+
64
78
  # wait if some connection(s) still need(s) more time to come down
65
79
  sleep wait_seconds_before_close if connections? || !stopped?
66
80
  end
67
81
 
68
82
  # Returns true if the server has stopped.
69
83
  def stopped?
70
- @tcp_server_threads.empty? && @tcp_servers.empty?
84
+ master? ? @workers.empty? && @tcp_server_threads.empty? && @tcp_servers.empty? : @tcp_server_threads.empty?
71
85
  end
72
86
 
73
87
  # Schedule a shutdown for the server
@@ -100,34 +114,67 @@ module MidiSmtpServer
100
114
  @processings.any?
101
115
  end
102
116
 
117
+ # Return if in pre-fork mode
118
+ def pre_fork?
119
+ @pre_fork > 1
120
+ end
121
+
122
+ # Return if this is the master process
123
+ def master?
124
+ !@is_forked
125
+ end
126
+
127
+ # Return if this is a forked worker process
128
+ def worker?
129
+ @is_forked
130
+ end
131
+
132
+ # Return number of forked worker processes
133
+ def workers
134
+ @workers.size
135
+ end
136
+
137
+ # Return if has active forked worker processes
138
+ def workers?
139
+ @workers.any?
140
+ end
141
+
103
142
  # Join with the server thread(s)
104
143
  # before joining the server threads, check and wait optionally a few seconds
105
144
  # to let the service(s) come up
106
145
  def join(sleep_seconds_before_join: 1)
107
146
  # check already existing TCPServers
108
147
  return if @tcp_servers.empty?
109
- # wait some seconds before joininig the upcoming threads
110
- # and check that all TCPServers gots one thread
111
- while (@tcp_server_threads.length < @tcp_servers.length) && sleep_seconds_before_join.positive?
112
- sleep_seconds_before_join -= 1
113
- sleep 1
114
- end
115
- # try to join any thread
116
- begin
117
- @tcp_server_threads.each(&:join)
148
+ # check number of processes to pre-fork
149
+
150
+ if pre_fork?
151
+ # create a number of pre-fork processes and attach and join threads within workers
152
+ @pre_fork.times do
153
+ # append worker pid to list of workers
154
+ @workers << fork do
155
+ # set state for a forked process
156
+ @is_forked = true
157
+ # just attach and join the threads to forked worker process
158
+ attach_threads
159
+ join_threads(sleep_seconds_before_join: sleep_seconds_before_join)
160
+ end
161
+ end
162
+ # Blocking wait until each worker process has been finished
163
+ @workers.each { |pid| Process.waitpid(pid) }
118
164
 
119
- # catch ctrl-c to stop service
120
- rescue Interrupt
165
+ else
166
+ # just join the threads to running single master process (default)
167
+ join_threads(sleep_seconds_before_join: sleep_seconds_before_join)
121
168
  end
122
169
  end
123
170
 
124
- # Array of ports on which to bind, set as string seperated by commata like '2525, 3535' or '2525:3535, 2525'
171
+ # Array of ports on which to bind, set as string separated by commata like '2525, 3535' or '2525:3535, 2525'
125
172
  def ports
126
173
  # prevent original array from being changed
127
174
  @ports.dup
128
175
  end
129
176
 
130
- # Array of hosts / ip_addresses on which to bind, set as string seperated by commata like 'name.domain.com, 127.0.0.1, ::1'
177
+ # Array of hosts / ip_addresses on which to bind, set as string separated by commata like 'name.domain.com, 127.0.0.1, ::1'
131
178
  def hosts
132
179
  # prevent original array from being changed
133
180
  @hosts.dup
@@ -139,7 +186,7 @@ module MidiSmtpServer
139
186
  @addresses.dup
140
187
  end
141
188
 
142
- # Current TLS OpenSSL::SSL::SSLContext when initalized by :TLS_OPTIONAL, :TLS_REQUIRED
189
+ # Current TLS OpenSSL::SSL::SSLContext when initialized by :TLS_OPTIONAL, :TLS_REQUIRED
143
190
  def ssl_context
144
191
  @tls&.ssl_context
145
192
  end
@@ -150,15 +197,17 @@ module MidiSmtpServer
150
197
  attr_reader :max_connections
151
198
  # CRLF handling based on conformity to RFC(2)822
152
199
  attr_reader :crlf_mode
200
+ # Time in seconds to sleep on IO::WaitReadable exception
201
+ attr_reader :io_waitreadable_sleep
153
202
  # Maximum time in seconds to wait for a complete incoming data line, as a FixNum
154
203
  attr_reader :io_cmd_timeout
155
204
  # Bytes to read non-blocking from socket into buffer, as a FixNum
156
205
  attr_reader :io_buffer_chunk_size
157
- # Maximum bytes to read as buffer before expecting completet incoming data line, as a FixNum
206
+ # Maximum bytes to read as buffer before expecting completed incoming data line, as a FixNum
158
207
  attr_reader :io_buffer_max_size
159
208
  # Flag if should do reverse DNS lookups on incoming connections
160
209
  attr_reader :do_dns_reverse_lookup
161
- # Authentification mode
210
+ # Authentication mode
162
211
  attr_reader :auth_mode
163
212
  # Encryption mode
164
213
  attr_reader :encrypt_mode
@@ -166,26 +215,31 @@ module MidiSmtpServer
166
215
  attr_reader :pipelining_extension
167
216
  # handle SMTP 8BITMIME and SMTPUTF8 extension
168
217
  attr_reader :internationalization_extensions
218
+ # handle PROXY connections
219
+ attr_reader :proxy_extension
169
220
 
170
- # logging object, may be overrriden by special loggers like YELL or others
221
+ # logging object, may be overridden by special loggers like YELL or others
171
222
  attr_reader :logger
172
223
 
173
224
  # Initialize SMTP Server class
174
225
  #
175
226
  # +ports+:: ports to listen on. Allows multiple ports like "2525, 3535" or "2525:3535, 2525". Default value = DEFAULT_SMTPD_PORT
176
227
  # +hosts+:: interface ip or hostname to listen on or "*" to listen on all interfaces, allows multiple hostnames and ip_addresses like "name.domain.com, 127.0.0.1, ::1". Default value = DEFAULT_SMTPD_HOST
228
+ # +pre_fork+:: number of processes to pre-fork to enable load balancing over multiple cores. Default value = DEFAULT_SMTPD_PRE_FORK
177
229
  # +max_processings+:: maximum number of simultaneous processed connections, this does not limit the number of concurrent TCP connections. Default value = DEFAULT_SMTPD_MAX_PROCESSINGS
178
230
  # +max_connections+:: maximum number of connections, this does limit the number of concurrent TCP connections (not set or nil => unlimited)
179
231
  # +crlf_mode+:: CRLF handling support (:CRLF_ENSURE [default], :CRLF_LEAVE, :CRLF_STRICT)
180
232
  # +do_dns_reverse_lookup+:: flag if this smtp server should do reverse DNS lookups on incoming connections
233
+ # +io_waitreadable_sleep+:: seconds to sleep in loop when no input data is available (DEFAULT_IO_WAITREADABLE_SLEEP)
181
234
  # +io_cmd_timeout+:: time in seconds to wait until complete line of data is expected (DEFAULT_IO_CMD_TIMEOUT, nil => disabled test)
182
235
  # +io_buffer_chunk_size+:: size of chunks (bytes) to read non-blocking from socket (DEFAULT_IO_BUFFER_CHUNK_SIZE)
183
236
  # +io_buffer_max_size+:: max size of buffer (max line length) until \lf ist expected (DEFAULT_IO_BUFFER_MAX_SIZE, nil => disabled test)
184
237
  # +pipelining_extension+:: set to true for support of SMTP PIPELINING extension (DEFAULT_PIPELINING_EXTENSION_ENABLED)
185
238
  # +internationalization_extensions+:: set to true for support of SMTP 8BITMIME and SMTPUTF8 extensions (DEFAULT_INTERNATIONALIZATION_EXTENSIONS_ENABLED)
239
+ # +proxy_extension+:: set to true for supporting PROXY connections (DEFAULT_PROXY_EXTENSION_ENABLED)
186
240
  # +auth_mode+:: enable builtin authentication support (:AUTH_FORBIDDEN [default], :AUTH_OPTIONAL, :AUTH_REQUIRED)
187
241
  # +tls_mode+:: enable builtin TLS support (:TLS_FORBIDDEN [default], :TLS_OPTIONAL, :TLS_REQUIRED)
188
- # +tls_cert_path+:: path to tls cerificate chain file
242
+ # +tls_cert_path+:: path to tls certificate chain file
189
243
  # +tls_key_path+:: path to tls key file
190
244
  # +tls_ciphers+:: allowed ciphers for connection
191
245
  # +tls_methods+:: allowed methods for protocol
@@ -196,15 +250,18 @@ module MidiSmtpServer
196
250
  def initialize(
197
251
  ports: DEFAULT_SMTPD_PORT,
198
252
  hosts: DEFAULT_SMTPD_HOST,
253
+ pre_fork: DEFAULT_SMTPD_PRE_FORK,
199
254
  max_processings: DEFAULT_SMTPD_MAX_PROCESSINGS,
200
255
  max_connections: nil,
201
256
  crlf_mode: nil,
202
257
  do_dns_reverse_lookup: nil,
258
+ io_waitreadable_sleep: nil,
203
259
  io_cmd_timeout: nil,
204
260
  io_buffer_chunk_size: nil,
205
261
  io_buffer_max_size: nil,
206
262
  pipelining_extension: nil,
207
263
  internationalization_extensions: nil,
264
+ proxy_extension: nil,
208
265
  auth_mode: nil,
209
266
  tls_mode: nil,
210
267
  tls_cert_path: nil,
@@ -216,7 +273,7 @@ module MidiSmtpServer
216
273
  logger: nil,
217
274
  logger_severity: nil
218
275
  )
219
- # create an exposed logger to forward loggings to the on_logging_event
276
+ # create an exposed logger to forward logging to the on_logging_event
220
277
  @logger = MidiSmtpServer::ForwardingLogger.new(method(:on_logging_event))
221
278
 
222
279
  # external logging
@@ -231,6 +288,11 @@ module MidiSmtpServer
231
288
  logger.warn('Deprecated: "logger" was set on new! Please use "on_logging_event" instead.')
232
289
  end
233
290
 
291
+ # initialize as master process
292
+ @is_forked = false
293
+ # no forked worker processes
294
+ @workers = []
295
+
234
296
  # list of TCPServers
235
297
  @tcp_servers = []
236
298
  # list of running threads
@@ -311,12 +373,16 @@ module MidiSmtpServer
311
373
  end
312
374
  end
313
375
 
376
+ # read pre_fork
377
+ @pre_fork = pre_fork
378
+ raise 'Number of processes to pre-fork (pre_fork) must be zero or a positive integer greater than 1!' unless @pre_fork.is_a?(Integer) && (@pre_fork.zero? || pre_fork?)
314
379
  # read max_processings
315
380
  @max_processings = max_processings
316
381
  raise 'Number of simultaneous processings (max_processings) must be a positive integer!' unless @max_processings.is_a?(Integer) && @max_processings.positive?
317
382
  # check max_connections
318
383
  @max_connections = max_connections
319
- raise 'Number of concurrent connections is lower than number of simultaneous processings!' if @max_connections && @max_connections < @max_processings
384
+ raise 'Number of concurrent connections (max_connections) must be nil or a positive integer!' unless @max_connections.nil? || (@max_connections.is_a?(Integer) && @max_connections.positive?)
385
+ raise 'Number of concurrent connections (max_connections) is lower than number of simultaneous processings (max_processings)!' if !@max_connections.nil? && @max_connections < @max_processings
320
386
 
321
387
  # check for crlf mode
322
388
  @crlf_mode = crlf_mode.nil? ? DEFAULT_CRLF_MODE : crlf_mode
@@ -328,6 +394,7 @@ module MidiSmtpServer
328
394
  @do_dns_reverse_lookup = do_dns_reverse_lookup.nil? ? true : do_dns_reverse_lookup
329
395
 
330
396
  # io and buffer settings
397
+ @io_waitreadable_sleep = io_waitreadable_sleep.nil? ? DEFAULT_IO_WAITREADABLE_SLEEP : io_waitreadable_sleep
331
398
  @io_cmd_timeout = io_cmd_timeout.nil? ? DEFAULT_IO_CMD_TIMEOUT : io_cmd_timeout
332
399
  @io_buffer_chunk_size = io_buffer_chunk_size.nil? ? DEFAULT_IO_BUFFER_CHUNK_SIZE : io_buffer_chunk_size
333
400
  @io_buffer_max_size = io_buffer_max_size.nil? ? DEFAULT_IO_BUFFER_MAX_SIZE : io_buffer_max_size
@@ -335,10 +402,12 @@ module MidiSmtpServer
335
402
  # smtp extensions
336
403
  @pipelining_extension = pipelining_extension.nil? ? DEFAULT_PIPELINING_EXTENSION_ENABLED : pipelining_extension
337
404
  @internationalization_extensions = internationalization_extensions.nil? ? DEFAULT_INTERNATIONALIZATION_EXTENSIONS_ENABLED : internationalization_extensions
405
+ @proxy_extension = proxy_extension.nil? ? DEFAULT_PROXY_EXTENSION_ENABLED : proxy_extension
406
+ require 'ipaddr' if @proxy_extension
338
407
 
339
- # check for authentification
408
+ # check for authentication
340
409
  @auth_mode = auth_mode.nil? ? DEFAULT_AUTH_MODE : auth_mode
341
- raise "Unknown authentification mode #{@auth_mode} was given!" unless AUTH_MODES.include?(@auth_mode)
410
+ raise "Unknown authentication mode #{@auth_mode} was given!" unless AUTH_MODES.include?(@auth_mode)
342
411
 
343
412
  # check for encryption
344
413
  @encrypt_mode = tls_mode.nil? ? DEFAULT_ENCRYPT_MODE : tls_mode
@@ -409,7 +478,7 @@ module MidiSmtpServer
409
478
  on_logging_event(ctx, Logger::DEBUG, "Client connect from #{ctx[:server][:remote_ip]}:#{ctx[:server][:remote_port]} to #{ctx[:server][:local_ip]}:#{ctx[:server][:local_port]}")
410
479
  end
411
480
 
412
- # event before DISONNECT
481
+ # event before DISCONNECT
413
482
  def on_disconnect_event(ctx)
414
483
  on_logging_event(ctx, Logger::DEBUG, "Client disconnect from #{ctx[:server][:remote_ip]}:#{ctx[:server][:remote_port]} on #{ctx[:server][:local_ip]}:#{ctx[:server][:local_port]}")
415
484
  end
@@ -420,13 +489,20 @@ module MidiSmtpServer
420
489
  # the value is not allowed to return CR nor LF chars and will be stripped
421
490
  def on_helo_event(ctx, helo_data) end
422
491
 
423
- # check the authentification on AUTH
492
+ # event on PROXY
493
+ # you may raise an exception if you want to block some addresses
494
+ # you also may change or add any value of the hash:
495
+ # {proto, source_ip, source_host, source_port, dest_ip, dest_host, dest_port}
496
+ # a returned value hash is set as ctx[:server][:proxy]
497
+ def on_proxy_event(ctx, proxy_data) end
498
+
499
+ # check the authentication on AUTH
424
500
  # if any value returned, that will be used for ongoing processing
425
501
  # otherwise the original value will be used for authorization_id
426
502
  def on_auth_event(ctx, authorization_id, authentication_id, authentication)
427
- # if authentification is used, override this event
503
+ # if authentication is used, override this event
428
504
  # and implement your own user management.
429
- # otherwise all authentifications are blocked per default
505
+ # otherwise all authentications are blocked per default
430
506
  on_logging_event(ctx, Logger::DEBUG, "Deny access from #{ctx[:server][:remote_ip]}:#{ctx[:server][:remote_port]} for #{authentication_id}" + (authorization_id == '' ? '' : "/#{authorization_id}") + " with #{authentication}")
431
507
  raise Smtpd535Exception
432
508
  end
@@ -473,8 +549,8 @@ module MidiSmtpServer
473
549
 
474
550
  protected
475
551
 
476
- # Start the listeners for all hosts
477
- def serve_service
552
+ # Prepare all listeners for all hosts
553
+ def create_service
478
554
  raise 'Service was already started' unless stopped?
479
555
 
480
556
  # set flag to signal shutdown by stop / shutdown command
@@ -485,12 +561,12 @@ module MidiSmtpServer
485
561
  # break address into ip_address and port and serve service
486
562
  ip_address = address.rpartition(':').first
487
563
  port = address.rpartition(':').last
488
- serve_service_on_ip_address_and_port(ip_address, port)
564
+ create_service_on_ip_address_and_port(ip_address, port)
489
565
  end
490
566
  end
491
567
 
492
- # Start the listener thread on single ip_address and port
493
- def serve_service_on_ip_address_and_port(ip_address, port)
568
+ # Prepare a listener on single ip_address and port
569
+ def create_service_on_ip_address_and_port(ip_address, port)
494
570
  # log information
495
571
  logger.info("Starting service on #{ip_address}:#{port}")
496
572
  # check that there is a specific ip_address defined
@@ -499,7 +575,47 @@ module MidiSmtpServer
499
575
  tcp_server = TCPServer.new(ip_address, port)
500
576
  # append this server to the list of TCPServers
501
577
  @tcp_servers << tcp_server
578
+ end
579
+
580
+ # Close and remove the given tcp_server
581
+ def remove_tcp_server(tcp_server)
582
+ begin
583
+ # drop the service
584
+ tcp_server.close
585
+ # remove from list
586
+ @tcp_servers.delete(tcp_server)
587
+ rescue StandardError
588
+ # ignore any error from here
589
+ end
590
+ end
591
+
592
+ # Join with the server thread(s)
593
+ # before joining the server threads, wait optionally a few seconds
594
+ # to let the service(s) come up
595
+ def join_threads(sleep_seconds_before_join: 1)
596
+ # wait some seconds before joining the upcoming threads
597
+ # and check that all TCPServers got one thread
598
+ while (@tcp_server_threads.length < @tcp_servers.length) && sleep_seconds_before_join.positive?
599
+ sleep_seconds_before_join -= 1
600
+ sleep 1
601
+ end
602
+ # try to join any thread
603
+ begin
604
+ @tcp_server_threads.each(&:join)
605
+
606
+ # catch ctrl-c to stop service
607
+ rescue Interrupt
608
+ end
609
+ end
502
610
 
611
+ # Create and attach threads to all listeners
612
+ def attach_threads
613
+ # loop for all TCPServers listener
614
+ @tcp_servers.each { |tcp_server| attach_thread(tcp_server) }
615
+ end
616
+
617
+ # Create and attach a thread to a listener
618
+ def attach_thread(tcp_server)
503
619
  # run thread until shutdown
504
620
  @tcp_server_threads << Thread.new do
505
621
  begin
@@ -527,7 +643,7 @@ module MidiSmtpServer
527
643
  ensure
528
644
  begin
529
645
  # always gracefully shutdown connection.
530
- # if the io object was overriden by the
646
+ # if the io object was overridden by the
531
647
  # result from serve_client() due to ssl
532
648
  # io, the ssl + io socket will be closed
533
649
  io.close
@@ -552,16 +668,7 @@ module MidiSmtpServer
552
668
  # log fatal error while starting new thread
553
669
  on_logging_event(nil, Logger::FATAL, "#{e} (#{e.class})".strip, err: e.clone)
554
670
  ensure
555
- begin
556
- # drop the service
557
- tcp_server.close
558
- # remove from list
559
- @tcp_servers.delete(tcp_server)
560
- # reset local var
561
- tcp_server = nil
562
- rescue StandardError
563
- # ignore any error from here
564
- end
671
+ # proper connection down?
565
672
  if shutdown?
566
673
  # wait for finishing opened connections
567
674
  @connections_mutex.synchronize do
@@ -604,7 +711,7 @@ module MidiSmtpServer
604
711
  on_connect_event(session[:ctx])
605
712
 
606
713
  # drop connection (respond 421) if too busy
607
- raise 'Abort connection while too busy, exceeding max_connections!' if max_connections && connections > max_connections
714
+ raise Smtpd421Exception, 'Abort connection while too busy, exceeding max_connections!' if !max_connections.nil? && connections > max_connections
608
715
 
609
716
  # check active processings for new client
610
717
  @connections_mutex.synchronize do
@@ -656,7 +763,7 @@ module MidiSmtpServer
656
763
  raise SmtpdIOTimeoutException if @io_cmd_timeout && Time.now.to_i - timestamp_timeout > @io_cmd_timeout
657
764
  # read chunks of input data until line-feed
658
765
  io_buffer << io.read_nonblock(@io_buffer_chunk_size)
659
- # check for buffersize
766
+ # check for buffer size
660
767
  raise SmtpdIOBufferOverrunException if @io_buffer_max_size && io_buffer.length > @io_buffer_max_size
661
768
  # check for lf in current io_buffer
662
769
  io_buffer_line_lf = io_buffer.index("\n")
@@ -665,7 +772,7 @@ module MidiSmtpServer
665
772
  # ignore exception when no input data is available yet
666
773
  rescue IO::WaitReadable
667
774
  # but wait a few moment to slow down system utilization
668
- sleep 0.1
775
+ sleep @io_waitreadable_sleep
669
776
  end
670
777
 
671
778
  # check if io_buffer is filled and contains already a line-feed
@@ -679,12 +786,12 @@ module MidiSmtpServer
679
786
  # process commands and handle special SmtpdExceptions
680
787
  begin
681
788
  # check for pipelining extension or violation
682
- raise Smtpd500PipeliningException unless @pipelining_extension || !io_buffer_line_lf || (session[:cmd_sequence] == :CMD_DATA)
789
+ raise Smtpd500PipeliningException unless !io_buffer_line_lf || @pipelining_extension || (proxy_extension && (session[:cmd_sequence] == :CMD_HELO)) || (session[:cmd_sequence] == :CMD_DATA)
683
790
 
684
791
  # handle input line based on @crlf_mode
685
792
  case crlf_mode
686
793
  when :CRLF_ENSURE
687
- # remove any \r or \n occurence from line
794
+ # remove any \r or \n occurrence from line
688
795
  line.delete!("\r\n")
689
796
  # log line, verbosity based on log severity and command sequence
690
797
  on_logging_event(session[:ctx], Logger::DEBUG, +'<<< ' << line << "\n") if session[:cmd_sequence] != :CMD_DATA
@@ -859,6 +966,88 @@ module MidiSmtpServer
859
966
  return "250 OK #{session[:ctx][:server][:helo_response].to_s.strip}".strip
860
967
  end
861
968
 
969
+ when @proxy_extension && (/^PROXY(\s+)/i)
970
+ # PROXY
971
+ # 250 Requested mail action okay, completed
972
+ # 421 <domain> Service not available, closing transmission channel
973
+ # 500 Syntax error, command unrecognised
974
+ # 501 Syntax error in parameters or arguments
975
+ # ---------
976
+ # Documentation at https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt
977
+ # syntax
978
+ # PROXY PROTO source-ip dest-ip source-port dest-port
979
+ # supported commands:
980
+ # PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535
981
+ # PROXY TCP6 ffff:f...f:ffff ffff:f...f:ffff 65535 65535
982
+ # PROXY UNKNOWN
983
+ # PROXY UNKNOWN ffff:f...f:ffff ffff:f...f:ffff 65535 65535
984
+ # ---------
985
+ # check valid command sequence
986
+ raise Smtpd503Exception if session[:cmd_sequence] != :CMD_HELO
987
+ # check valid command
988
+ raise Smtpd421Exception, 'Abort connection while illegal PROXY command!' unless line.match?(/^PROXY(\s+)(UNKNOWN(|(\s+).*)|TCP(4|6)(\s+)([0-9a-f.:]+)(\s+)([0-9a-f.:]+)(\s+)([0-9]+)(\s+)([0-9]+)(\s*))$/i)
989
+ # check command usage is allowed only once
990
+ raise Smtpd421Exception, 'Abort connection while PROXY already set!' if session[:ctx][:server][:proxy]
991
+ # get values from proxy command
992
+ cmd_data = line.gsub(/^PROXY\ /i, '').strip.gsub(/\s+/, ' ').split
993
+ # create an empty hash to inspect by event
994
+ proxy_data = {
995
+ proto: cmd_data[0].upcase,
996
+ source_ip: nil,
997
+ source_host: nil,
998
+ source_port: nil,
999
+ dest_ip: nil,
1000
+ dest_host: nil,
1001
+ dest_port: nil
1002
+ }
1003
+ # test proto
1004
+ unless proxy_data[:proto] == 'UNKNOWN'
1005
+ begin
1006
+ # try to build valid addresses from given strings
1007
+ proxy_data[:source_ip] = IPAddr.new(cmd_data[1])
1008
+ proxy_data[:source_port] = cmd_data[3].to_i
1009
+ proxy_data[:dest_ip] = IPAddr.new(cmd_data[2])
1010
+ proxy_data[:dest_port] = cmd_data[4].to_i
1011
+ # check that given addresses correct by type
1012
+ if proxy_data[:proto] == 'TCP4'
1013
+ raise unless proxy_data[:source_ip].ipv4?
1014
+ raise unless proxy_data[:dest_ip].ipv4?
1015
+ else
1016
+ raise unless proxy_data[:source_ip].ipv6?
1017
+ raise unless proxy_data[:dest_ip].ipv6?
1018
+ end
1019
+ # check that ports within valid ranges
1020
+ raise unless proxy_data[:source_port].between?(1, 65_535)
1021
+ raise unless proxy_data[:dest_port].between?(1, 65_535)
1022
+
1023
+ # update hash to inspect by event
1024
+ # normalize ip addresses
1025
+ proxy_data[:source_ip] = proxy_data[:source_ip].to_s
1026
+ proxy_data[:source_host] = proxy_data[:source_ip]
1027
+ proxy_data[:dest_ip] = proxy_data[:dest_ip].to_s
1028
+ proxy_data[:dest_host] = proxy_data[:dest_ip]
1029
+
1030
+ rescue StandardError
1031
+ # change exception into Smtpd exception and drop connection
1032
+ raise Smtpd421Exception, 'Abort connection for unsupported PROXY parameters!'
1033
+ end
1034
+ end
1035
+
1036
+ # call event to handle data
1037
+ return_value = on_proxy_event(session[:ctx], proxy_data)
1038
+ if return_value
1039
+ # overwrite data with returned value
1040
+ proxy_data = return_value
1041
+ end
1042
+ # if no error raised, append to server hash
1043
+ session[:ctx][:server][:proxy] = proxy_data
1044
+
1045
+ # reply nothing
1046
+ # otherwise on buffering clients or enabled feature pipelining
1047
+ # the original client will receive unhandleable responses
1048
+ # and gets interrupted
1049
+ return ''
1050
+
862
1051
  when /^STARTTLS\s*$/i
863
1052
  # STARTTLS
864
1053
  # 220 Ready to start TLS
@@ -1201,6 +1390,7 @@ module MidiSmtpServer
1201
1390
  remote_host: +'',
1202
1391
  remote_ip: +'',
1203
1392
  remote_port: +'',
1393
+ proxy: nil,
1204
1394
  helo: +'',
1205
1395
  helo_response: +'',
1206
1396
  connected: +'',
@@ -1235,7 +1425,7 @@ module MidiSmtpServer
1235
1425
  )
1236
1426
  end
1237
1427
 
1238
- # handle plain authentification
1428
+ # handle plain authentication
1239
1429
  def process_auth_plain(session, encoded_auth_response)
1240
1430
  begin
1241
1431
  # extract auth id (and password)
metadata CHANGED
@@ -1,17 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: midi-smtp-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Freudenberg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-12 00:00:00.000000000 Z
11
+ date: 2023-08-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: A small and highly customizable ruby SMTP-Server class with builtin support
14
- for AUTH and SSL/STARTTLS.
13
+ description: MidiSmtpServer is the highly customizable ruby SMTP-Server and SMTP-Service
14
+ library with builtin support for AUTH and SSL/STARTTLS, 8BITMIME and SMTPUTF8, IPv4
15
+ and IPv6 and additional features.
15
16
  email: develop.rb.midi-smtp-server@4commerce.net
16
17
  executables: []
17
18
  extensions: []
@@ -25,7 +26,7 @@ files:
25
26
  - lib/midi-smtp-server/logger.rb
26
27
  - lib/midi-smtp-server/tls-transport.rb
27
28
  - lib/midi-smtp-server/version.rb
28
- homepage:
29
+ homepage: https://4commerce-technologies-ag.github.io/midi-smtp-server
29
30
  licenses:
30
31
  - MIT
31
32
  metadata:
@@ -33,7 +34,7 @@ metadata:
33
34
  source_code_uri: https://github.com/4commerce-technologies-AG/midi-smtp-server
34
35
  changelog_uri: https://github.com/4commerce-technologies-AG/midi-smtp-server#changes-and-updates
35
36
  bug_tracker_uri: https://github.com/4commerce-technologies-AG/midi-smtp-server/issues
36
- documentation_uri: https://www.rubydoc.info/gems/midi-smtp-server/3.0.3
37
+ documentation_uri: https://www.rubydoc.info/gems/midi-smtp-server/3.2.1
37
38
  wiki_uri: https://midi-smtp-server.readthedocs.io/
38
39
  post_install_message:
39
40
  rdoc_options: []
@@ -50,7 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
51
  - !ruby/object:Gem::Version
51
52
  version: '0'
52
53
  requirements: []
53
- rubygems_version: 3.2.15
54
+ rubygems_version: 3.4.10
54
55
  signing_key:
55
56
  specification_version: 4
56
57
  summary: MidiSmtpServer Class