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:
parent
dbbafd320c
commit
f7cfc46ae1
2 changed files with 26 additions and 9 deletions
|
|
@ -7,7 +7,9 @@
|
||||||
|
|
||||||
## Standard library additions and changes
|
## 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
|
## Language changes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,6 @@ proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[string] {.multisync.} =
|
||||||
## `SMTP extensions<https://en.wikipedia.org/wiki/Extended_SMTP>`_.
|
## `SMTP extensions<https://en.wikipedia.org/wiki/Extended_SMTP>`_.
|
||||||
##
|
##
|
||||||
## See `checkReply(reply)<#checkReply,AsyncSmtp,string>`_.
|
## See `checkReply(reply)<#checkReply,AsyncSmtp,string>`_.
|
||||||
|
|
||||||
result = await smtp.sock.recvLine()
|
result = await smtp.sock.recvLine()
|
||||||
if smtp.debug:
|
if smtp.debug:
|
||||||
echo("S:" & result)
|
echo("S:" & result)
|
||||||
|
|
@ -171,8 +170,7 @@ proc `$`*(msg: Message): string =
|
||||||
result.add("\c\L")
|
result.add("\c\L")
|
||||||
result.add(msg.msgBody)
|
result.add(msg.msgBody)
|
||||||
|
|
||||||
proc newSmtp*(useSsl = false, debug = false,
|
proc newSmtp*(useSsl = false, debug = false, sslContext: SslContext = nil): Smtp =
|
||||||
sslContext: SslContext = nil): Smtp =
|
|
||||||
## Creates a new `Smtp` instance.
|
## Creates a new `Smtp` instance.
|
||||||
new result
|
new result
|
||||||
result.debug = debug
|
result.debug = debug
|
||||||
|
|
@ -186,12 +184,10 @@ proc newSmtp*(useSsl = false, debug = false,
|
||||||
else:
|
else:
|
||||||
{.error: "SMTP module compiled without SSL support".}
|
{.error: "SMTP module compiled without SSL support".}
|
||||||
|
|
||||||
proc newAsyncSmtp*(useSsl = false, debug = false,
|
proc newAsyncSmtp*(useSsl = false, debug = false, sslContext: SslContext = nil): AsyncSmtp =
|
||||||
sslContext: SslContext = nil): AsyncSmtp =
|
|
||||||
## Creates a new `AsyncSmtp` instance.
|
## Creates a new `AsyncSmtp` instance.
|
||||||
new result
|
new result
|
||||||
result.debug = debug
|
result.debug = debug
|
||||||
|
|
||||||
result.sock = newAsyncSocket()
|
result.sock = newAsyncSocket()
|
||||||
if useSsl:
|
if useSsl:
|
||||||
when compiledWithSsl:
|
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
|
## would need to call when using this module. One exception to
|
||||||
## this is if you are implementing any
|
## this is if you are implementing any
|
||||||
## `SMTP extensions<https://en.wikipedia.org/wiki/Extended_SMTP>`_.
|
## `SMTP extensions<https://en.wikipedia.org/wiki/Extended_SMTP>`_.
|
||||||
|
|
||||||
var line = await smtp.debugRecv()
|
var line = await smtp.debugRecv()
|
||||||
if not line.startsWith(reply):
|
if not line.startsWith(reply):
|
||||||
await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line)
|
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.debugSend("HELO " & smtp.address & "\c\L")
|
||||||
await smtp.checkReply("250")
|
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,
|
proc connect*(smtp: Smtp | AsyncSmtp,
|
||||||
address: string, port: Port) {.multisync.} =
|
address: string, port: Port) {.multisync.} =
|
||||||
## Establishes a connection with a SMTP server.
|
## Establishes a connection with a SMTP server.
|
||||||
|
|
@ -237,7 +248,9 @@ proc connect*(smtp: Smtp | AsyncSmtp,
|
||||||
smtp.address = address
|
smtp.address = address
|
||||||
await smtp.sock.connect(address, port)
|
await smtp.sock.connect(address, port)
|
||||||
await smtp.checkReply("220")
|
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.} =
|
proc startTls*(smtp: Smtp | AsyncSmtp, sslContext: SslContext = nil) {.multisync.} =
|
||||||
## Put the SMTP connection in TLS (Transport Layer Security) mode.
|
## 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)
|
getSSLContext().wrapConnectedSocket(smtp.sock, handshakeAsClient)
|
||||||
else:
|
else:
|
||||||
sslContext.wrapConnectedSocket(smtp.sock, handshakeAsClient)
|
sslContext.wrapConnectedSocket(smtp.sock, handshakeAsClient)
|
||||||
await smtp.helo()
|
let speaksEsmtp = await smtp.ehlo()
|
||||||
|
if not speaksEsmtp:
|
||||||
|
await smtp.helo()
|
||||||
else:
|
else:
|
||||||
{.error: "SMTP module compiled without SSL support".}
|
{.error: "SMTP module compiled without SSL support".}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue