Repository navigation
Bind net/smtp: Net::SMTP over the real socket/TLS transport - #205
Closed
tannevaled wants to merge 1 commit into
Closed
tannevaled wants to merge 1 commit into
tannevaled wants to merge 1 commit into
Conversation
Wire github.com/go-ruby-net-smtp/net-smtp (the MRI-byte-exact SMTP codec: command grammar, DATA dot-stuffing, reply parser, EHLO capability parse, SASL PLAIN/LOGIN/CRAM-MD5) into rbgo so `require "net/smtp"` provides a native Net::SMTP with no .rb file. The codec deliberately leaves out the socket, so — unlike the redis/pg bindings' injected-IO seam — the transport here is rbgo's real socket layer (socket.go): Net::SMTP#start dials a TCPSocket, wraps it in a smtpConn satisfying the library's Conn seam, and drives netsmtp.Session against it. STARTTLS upgrades the same socket in place through the crypto/tls handshake the net/http transport already uses; implicit TLS (SMTPS) wraps on connect. Ruby surface: Net::SMTP.new / .start (block + non-block, positional and keyword credentials, tls:/starttls:), start/finish, send_message / sendmail, open_message_stream / ready (with a puts/print/write/<< adapter), data (string or block), the low-level ehlo/helo/mailfrom/rcptto/rcptto_list/rset, authenticate (:plain/:login/:cram_md5), the esmtp/tls/starttls config and capability predicates, timeouts, and a Net::SMTP::Response view. The Net::SMTPError family (SMTPError < ProtocolError; ServerBusy/Syntax/ Authentication/Fatal/Unknown/UnsupportedCommand) is registered so a codec error rescues as its MRI-faithful class. Tests drive an in-process scripted SMTP server (plaintext, STARTTLS-upgrade and implicit-TLS variants with a generated self-signed cert) plus Go-level unit tests for the connless/nil-session branches — deterministic, no real network, goroutines joined on cleanup. 100% coverage of the new files; full internal/vm + internal/object suites green; gofmt/vet/-race clean; builds on all six 64-bit arches. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
Author
|
Superseded by the net-wave consolidation PR (single merge onto main; shared builtins/require/object_model). Work preserved verbatim; branch kept. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Wires
github.com/go-ruby-net-smtp/net-smtp— the MRI-byte-exact SMTP codec (command grammar, DATA dot-stuffing, reply parser, EHLO capability parse, SASL PLAIN/LOGIN/CRAM-MD5) — into rbgo sorequire "net/smtp"provides a nativeNet::SMTPwith no.rbfile.Transport
The codec deliberately leaves out the socket, so — unlike the redis/pg bindings' injected-IO seam — the transport here is rbgo's real socket layer (
socket.go):Net::SMTP#startdials aTCPSocket, wraps it in asmtpConnsatisfying the library'sConnseam (WriteLine/ReadLine/WriteRaw/StartTLS), and drivesnetsmtp.Sessionagainst it exactly the way MRI drives its@socket.STARTTLSupgrades the same socket in place through thecrypto/tlshandshake thenet/httptransport already uses; implicit TLS (SMTPS,tls: true) wraps on connect. TLS defaults toVERIFY_NONE, matching the transport default (full cert-store verification is a follow-up).Ruby surface bound
Net::SMTP.new(addr[, port]),Net::SMTP.start(...)(block + non-block; positional and keyword credentials;tls:/starttls:),default_port/default_tls_port/default_ssl_port/default_submission_portstart/finish/started?send_message/sendmail,open_message_stream/ready(yields aputs/print/write/<<adapter),data(string or block)ehlo/helo/mailfrom/rcptto/rcptto_list/rset,authenticate(:plain/:login/:cram_md5)esmtp?/esmtp=,enable_tls/enable_ssl/disable_tls,enable_starttls/enable_starttls_auto/disable_starttls,tls?/ssl?/starttls?/starttls_auto?/starttls_always?(exclusivity enforced),open_timeout/read_timeout,capable_starttls?/capable_plain_auth?/capable_login_auth?/capable_cram_md5_auth?/capable_auth_typesNet::SMTP::Responseview (status/string/message/success?/continue?)Net::SMTPErrorfamily (SMTPError < ProtocolError;ServerBusy/Syntax/Authentication/Fatal/Unknown/UnsupportedCommand), so a codec error rescues as its MRI-faithful classActionMailer's
SMTPDeliverycould now be backed by this — left as a follow-up (not wired here).Wiring
registerNetSMTP()in the builtins bootstrap (afterregisterSocket/registerNetHTTP),providedFeatures["net/smtp"],classOfcases for the three new value types, mirroring the redis/pg/net-http split.Tests
Tests drive an in-process scripted SMTP server (plaintext, STARTTLS-upgrade, and implicit-TLS variants using a generated self-signed cert) plus Go-level unit tests for the connless / nil-session branches — deterministic, no real network, goroutines joined on cleanup.
net_smtp.go+net_smtp_bind.gointernal/vm+internal/objectsuites green (76.8s / 0.3s)gofmt -lempty,go vetclean,-raceclean on the new testsCGO=0,
GOWORK=off, go 1.26.4, BSD-3-Clause.🤖 Generated with Claude Code