Added support for sending "ehlo" and receiving multiline "ehlo" response. (#19077)

* Added support for sending "ehlo"
and receiving multiline "ehlo" response.

Signed-off-by: David Krause <enthus1ast@users.noreply.github.com>

* fix typo

Signed-off-by: David Krause <enthus1ast@users.noreply.github.com>

* send "EHLO" first, if not supported, send "HELO" to smtp server.

Signed-off-by: David Krause <enthus1ast@users.noreply.github.com>

* fix english

Signed-off-by: David Krause <enthus1ast@users.noreply.github.com>

* add changelog entry for smtp `ehlo`

Signed-off-by: David Krause <enthus1ast@users.noreply.github.com>

* recvEhlo must not be exported

Signed-off-by: David Krause <enthus1ast@users.noreply.github.com>
This commit is contained in:
David Krause
2021-11-03 09:14:59 +01:00
committed by GitHub
parent dbbafd320c
commit f7cfc46ae1
2 changed files with 26 additions and 9 deletions

View File

@@ -7,7 +7,9 @@
## Standard library additions and changes
## `std/smtp`
- Sends `ehlo` first. If the mail server does not understand, it sends `helo` as a fallback.
## Language changes

View File

@@ -100,7 +100,6 @@ proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[string] {.multisync.} =
## `SMTP extensions<https://en.wikipedia.org/wiki/Extended_SMTP>`_.
##
## See `checkReply(reply)<#checkReply,AsyncSmtp,string>`_.
result = await smtp.sock.recvLine()
if smtp.debug:
echo("S:" & result)
@@ -171,8 +170,7 @@ proc `$`*(msg: Message): string =
result.add("\c\L")
result.add(msg.msgBody)
proc newSmtp*(useSsl = false, debug = false,
sslContext: SslContext = nil): Smtp =
proc newSmtp*(useSsl = false, debug = false, sslContext: SslContext = nil): Smtp =
## Creates a new `Smtp` instance.
new result
result.debug = debug
@@ -186,12 +184,10 @@ proc newSmtp*(useSsl = false, debug = false,
else:
{.error: "SMTP module compiled without SSL support".}
proc newAsyncSmtp*(useSsl = false, debug = false,
sslContext: SslContext = nil): AsyncSmtp =
proc newAsyncSmtp*(useSsl = false, debug = false, sslContext: SslContext = nil): AsyncSmtp =
## Creates a new `AsyncSmtp` instance.
new result
result.debug = debug
result.sock = newAsyncSocket()
if useSsl:
when compiledWithSsl:
@@ -220,7 +216,6 @@ proc checkReply*(smtp: Smtp | AsyncSmtp, reply: string) {.multisync.} =
## would need to call when using this module. One exception to
## this is if you are implementing any
## `SMTP extensions<https://en.wikipedia.org/wiki/Extended_SMTP>`_.
var line = await smtp.debugRecv()
if not line.startsWith(reply):
await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line)
@@ -230,6 +225,22 @@ proc helo*(smtp: Smtp | AsyncSmtp) {.multisync.} =
await smtp.debugSend("HELO " & smtp.address & "\c\L")
await smtp.checkReply("250")
proc recvEhlo(smtp: Smtp | AsyncSmtp): Future[bool] {.multisync.} =
## Skips "250-" lines, read until "250 " found.
## Return `true` if server supports `EHLO`, false otherwise.
while true:
var line = await smtp.sock.recvLine()
if smtp.debug:
echo("S:" & line)
if line.startsWith("250-"): continue
elif line.startsWith("250 "): return true # last line
else: return false
proc ehlo*(smtp: Smtp | AsyncSmtp): Future[bool] {.multisync.} =
## Sends EHLO request.
await smtp.debugSend("EHLO " & smtp.address & "\c\L")
return await smtp.recvEhlo()
proc connect*(smtp: Smtp | AsyncSmtp,
address: string, port: Port) {.multisync.} =
## Establishes a connection with a SMTP server.
@@ -237,7 +248,9 @@ proc connect*(smtp: Smtp | AsyncSmtp,
smtp.address = address
await smtp.sock.connect(address, port)
await smtp.checkReply("220")
await smtp.helo()
let speaksEsmtp = await smtp.ehlo()
if not speaksEsmtp:
await smtp.helo()
proc startTls*(smtp: Smtp | AsyncSmtp, sslContext: SslContext = nil) {.multisync.} =
## Put the SMTP connection in TLS (Transport Layer Security) mode.
@@ -249,7 +262,9 @@ proc startTls*(smtp: Smtp | AsyncSmtp, sslContext: SslContext = nil) {.multisync
getSSLContext().wrapConnectedSocket(smtp.sock, handshakeAsClient)
else:
sslContext.wrapConnectedSocket(smtp.sock, handshakeAsClient)
await smtp.helo()
let speaksEsmtp = await smtp.ehlo()
if not speaksEsmtp:
await smtp.helo()
else:
{.error: "SMTP module compiled without SSL support".}