Skip to content

Reset SMTP error state before opening a fresh session - #101

Open
OskarEichler wants to merge 2 commits into
ruby:masterfrom
OskarEichler:codex/retry-smtp
Open

Reset SMTP error state before opening a fresh session#101
OskarEichler wants to merge 2 commits into
ruby:masterfrom
OskarEichler:codex/retry-smtp

Conversation

@OskarEichler

Copy link
Copy Markdown

Summary

Clear the previous critical-section error flag before opening a fresh SMTP session. A failed non-block start otherwise leaves the flag set; a later start can report success while skipping the new connection's greeting, EHLO and subsequent commands.

Reproduction

require 'net/smtp'
# A deterministic offline reproduction of the same failed-greeting state.
smtp = Net::SMTP.new('example.invalid', starttls: false)
socket = Object.new
def socket.close = nil
smtp.define_singleton_method(:tcp_socket) { |*| socket }
smtp.define_singleton_method(:new_internet_message_io) { |s| s }
greetings = 0
smtp.define_singleton_method(:recv_response) do
  greetings += 1
  raise EOFError if greetings == 1
  Net::SMTP::Response.parse('220 fixture')
end
smtp.define_singleton_method(:do_helo) { |*| nil }
begin
  smtp.start
rescue EOFError
end
smtp.start
p greetings # before: 1; after: 2
# No real network or delivery occurs in this isolated reproduction.

Verification

  • 16 focused checks also use a bounded real localhost listener: the first connection closes before its greeting; retrying the same SMTP object (block and non-block forms) reads the second greeting, transmits EHLO, records SIZE and sends RSET. Baseline falsely reports RSET success without transmitting it. Six failed expectations before; zero after.
  • Existing rake test: 95 tests, 170 assertions, zero failures/errors, on baseline and this isolated branch, Ruby 4.0.6 via rbenv. Existing local TLS cases are included.
  • Supplemental RuboCop Lint has the same six existing findings; Ruby syntax and git diff --check pass. No new/modified repository tests, dependencies or workflow settings.
  • Independent branch based on c2e9102e1f199a5a10e5261a776d752e64cc130f; runtime matches released 0.5.1. External focused checks were used under the consumer repository's no-new-tests policy.

Compatibility and limits

No public API change and no automatic retry is introduced. Only a caller-initiated new session clears the previous error state. Failed exchanges on an existing session remain non-resumable; this patch does not reset the documented ESMTP fallback setting. Other Ruby/OS runtimes were not run locally. No production or external SMTP delivery was used. Maintainer CI status is separate from these local checks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant