From 8fb77a7c40cc87eb941de8160e44788db91e5076 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 16:42:19 +0300 Subject: [PATCH] net.smtp: separate config from client struct (fixes #19928) --- examples/smtp/mail.v | 2 +- vlib/net/smtp/smtp.v | 27 +++++++++++++-------------- vlib/net/smtp/smtp_test.v | 19 +++++++++++++++++-- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/examples/smtp/mail.v b/examples/smtp/mail.v index 118e1b2f3..4a41582c8 100644 --- a/examples/smtp/mail.v +++ b/examples/smtp/mail.v @@ -19,7 +19,7 @@ fn main() { to := os.input('To: ') subject := os.input('Subject: ') body := os.input('Body: ') - client_cfg := smtp.Client{ + client_cfg := smtp.Config{ server: mailserver from: from port: mailport diff --git a/vlib/net/smtp/smtp.v b/vlib/net/smtp/smtp.v index b703a2aa9..3d71224a1 100644 --- a/vlib/net/smtp/smtp.v +++ b/vlib/net/smtp/smtp.v @@ -28,12 +28,8 @@ pub enum BodyType { html } -// Client configures an SMTP connection. `timeout` applies to the underlying TCP reads and writes. -pub struct Client { -mut: - conn net.TcpConn - ssl_conn &ssl.SSLConn = unsafe { nil } - reader ?&io.BufferedReader +// Config stores the settings used to connect a new SMTP client. +pub struct Config { pub: server string port int = 25 @@ -42,7 +38,14 @@ pub: from string ssl bool starttls bool - timeout time.Duration = net.tcp_default_read_timeout +} + +pub struct Client { + Config +mut: + conn net.TcpConn + ssl_conn &ssl.SSLConn = unsafe { nil } + reader ?&io.BufferedReader pub mut: is_open bool encrypted bool @@ -70,13 +73,13 @@ pub: } // new_client returns a new SMTP client and connects to it -pub fn new_client(config Client) !&Client { +pub fn new_client(config Config) !&Client { if config.ssl && config.starttls { return error('Can not use both implicit SSL and STARTTLS') } mut c := &Client{ - ...config + Config: config } c.reconnect()! return c @@ -88,11 +91,7 @@ pub fn (mut c Client) reconnect() ! { return error('Already connected to server') } - mut conn := net.dial_tcp('${c.server}:${c.port}') or { - return error('Connecting to server failed') - } - conn.set_read_timeout(c.timeout) - conn.set_write_timeout(c.timeout) + conn := net.dial_tcp('${c.server}:${c.port}') or { return error('Connecting to server failed') } c.conn = conn if c.ssl || c.encrypted { diff --git a/vlib/net/smtp/smtp_test.v b/vlib/net/smtp/smtp_test.v index 603a471f9..2c6f6e9a5 100644 --- a/vlib/net/smtp/smtp_test.v +++ b/vlib/net/smtp/smtp_test.v @@ -10,7 +10,7 @@ fn fn_errors(mut c smtp.Client, m smtp.Mail) bool { } fn send_mail(starttls bool) { - client_cfg := smtp.Client{ + client_cfg := smtp.Config{ server: 'smtp.mailtrap.io' port: 465 from: 'dev@vlang.io' @@ -108,7 +108,7 @@ fn test_smtp_implicit_ssl() { return } - client_cfg := smtp.Client{ + client_cfg := smtp.Config{ server: 'smtp.gmail.com' port: 465 from: '' @@ -125,6 +125,21 @@ fn test_smtp_implicit_ssl() { assert client.is_open && client.encrypted } +fn test_new_client_rejects_conflicting_tls_modes() { + client_cfg := smtp.Config{ + server: 'smtp.example.com' + ssl: true + starttls: true + } + + smtp.new_client(client_cfg) or { + assert err.msg() == 'Can not use both implicit SSL and STARTTLS' + return + } + + assert false +} + fn test_smtp_multiple_recipients() { $if !network ? { return -- 2.39.5