# src/smtp

Theme:

- Manual
- Standard library
- Index
- Compiler docs
- Fusion docs
- devel, stable

Search:

Note: In order to use this module, run `nimble install smtp`.

This module implements the SMTP client protocol as specified by RFC 5321, this can be used to send mail to any SMTP Server.

This module also implements the protocol used to format messages, as specified by RFC 2822.

Example gmail use:

    var msg = createMessage("Hello from Nim's SMTP",
                            "Hello!.\n Is this awesome or what?",
                            @["foo@gmail.com"])
    let smtpConn = newSmtp(useSsl = true, debug=true)
    smtpConn.connect("smtp.gmail.com", Port 465)
    smtpConn.auth("username", "password")
    smtpConn.sendmail("username@gmail.com", @["foo@gmail.com"], $msg)

Example for startTls use:

    var msg = createMessage("Hello from Nim's SMTP",
                            "Hello!.\n Is this awesome or what?",
                            @["foo@gmail.com"])
    let smtpConn = newSmtp(debug=true)
    smtpConn.connect("smtp.mailtrap.io", Port 2525)
    smtpConn.startTls()
    smtpConn.auth("username", "password")
    smtpConn.sendmail("username@gmail.com", @["foo@gmail.com"], $msg)

For SSL support this module relies on OpenSSL. If you want to enable SSL, compile with `-d:ssl`.

# Types

    AsyncSmtp = SmtpBase[AsyncSocket]

    Email = object
      address*: string

    Message = object

    ReplyError = object of IOError

    Smtp = SmtpBase[Socket]

# Procs

    proc `$`(email: Email): string {....raises: [], tags: [], forbids: [].}

  stringify for `Email`.

    proc `$`(msg: Message): string {....raises: [], tags: [], forbids: [].}

  stringify for `Message`.

    proc auth(smtp: AsyncSmtp; username, password: string): owned(Future[void]) {.
        ...stackTrace: false, raises: [Exception, SslError, ValueError],
        tags: [RootEffect], forbids: [].}

  Sends an AUTH command to the server to login as the `username` using `password`. May fail with ReplyError.

    proc auth(smtp: Smtp; username, password: string) {.
        ...raises: [SslError, OSError, TimeoutError, ReplyError],
        tags: [WriteIOEffect, ReadIOEffect, TimeEffect], forbids: [].}

    proc checkReply(smtp: AsyncSmtp; reply: string): owned(Future[void]) {.
        ...stackTrace: false, raises: [Exception, ValueError, SslError],
        tags: [RootEffect], forbids: [].}

  Calls debugRecv and checks that the received data starts with `reply`. If the received data does not start with `reply`, then a `QUIT` command will be sent to the SMTP server and a `ReplyError` exception will be raised.

  This is a lower level proc and not something that you typically would need to call when using this module. One exception to this is if you are implementing any SMTP extensions.

    proc checkReply(smtp: Smtp; reply: string) {.
        ...raises: [TimeoutError, OSError, SslError, ReplyError],
        tags: [ReadIOEffect, TimeEffect, WriteIOEffect], forbids: [].}

    proc close(smtp: AsyncSmtp): owned(Future[void]) {....stackTrace: false,
        raises: [Exception, SslError, ValueError, LibraryError], tags: [RootEffect],
        forbids: [].}

  Disconnects from the SMTP server and closes the socket.

    proc close(smtp: Smtp) {....raises: [SslError, OSError, LibraryError, Exception],
                             tags: [WriteIOEffect, RootEffect], forbids: [].}

    proc connect(smtp: AsyncSmtp; address: string; port: Port): owned(
        Future[void]) {....stackTrace: false, raises: [Exception, OSError, IOError,
        ValueError, SslError], tags: [RootEffect], forbids: [].}

  Establishes a connection with a SMTP server. May fail with ReplyError or with a socket error.

    proc connect(smtp: Smtp; address: string; port: Port) {.
        ...raises: [OSError, SslError, TimeoutError, ReplyError],
        tags: [ReadIOEffect, RootEffect, TimeEffect, WriteIOEffect], forbids: [].}

    proc createEmail(address: string; name: string = ""): Email {....raises: [],
        tags: [], forbids: [].}

  Creates a new email address

  You need to make sure that `address` and `name` (if specified) do not contain any newline characters. Failing to do so will raise `AssertionDefect`.

    proc createMessage(mSubject, mBody: string; mTo, mCc: seq[string] = @[]): Message {.
        ...deprecated: "use `createMessage` overloads with a `sender`", raises: [],
        tags: [], forbids: [].}

  Deprecated: use `createMessage` overloads with a `sender`

  Alternate version of the above.

  You need to make sure that `mSubject`, `mTo` and `mCc` don't contain any newline characters. Failing to do so will raise `AssertionDefect`.

    proc createMessage(mSubject, mBody: string; mTo, mCc: seq[string];
                       otherHeaders: openArray[tuple[name, value: string]]): Message {.
        ...deprecated: "use `createMessage` overloads with a `sender`", raises: [],
        tags: [], forbids: [].}

  Deprecated: use `createMessage` overloads with a `sender`

  Creates a new MIME compliant message.

  You need to make sure that `mSubject`, `mTo` and `mCc` don't contain any newline characters. Failing to do so will raise `AssertionDefect`.

    proc createMessage[T: Email | string](mSubject, mBody: string; sender: T;
                                          mTo: seq[T] = @[]; mCc: seq[T] = @[];
                                          mBcc: seq[T] = @[];
                                          mReplyTo: seq[T] = @[]; otherHeaders: openArray[
        tuple[name, value: string]] = @[]): Message

  Creates a new MIME compliant message.

  You need to make sure that `mSubject` does not contain any newline characters. Failing to do so will raise `AssertionDefect`.

    proc debugRecv(smtp: AsyncSmtp): Future[string] {....stackTrace: false,
        raises: [Exception, ValueError, SslError], tags: [RootEffect], forbids: [].}

  Receives a line of data from the socket connected to the SMTP server.

  If the `smtp` object was created with `debug` enabled, debugRecv will invoke `echo("S:" & result.string)` after the data is received.

  This is a lower level proc and not something that you typically would need to call when using this module. One exception to this is if you are implementing any SMTP extensions.

  See checkReply(reply).

    proc debugRecv(smtp: Smtp): string {....raises: [TimeoutError, OSError, SslError],
                                         tags: [ReadIOEffect, TimeEffect],
                                         forbids: [].}

    proc debugSend(smtp: AsyncSmtp; cmd: string): owned(Future[void]) {.
        ...stackTrace: false, raises: [Exception, SslError, ValueError],
        tags: [RootEffect], forbids: [].}

  Sends `cmd` on the socket connected to the SMTP server.

  If the `smtp` object was created with `debug` enabled, debugSend will invoke `echo("C:" & cmd)` before sending.

  This is a lower level proc and not something that you typically would need to call when using this module. One exception to this is if you are implementing any SMTP extensions.

    proc debugSend(smtp: Smtp; cmd: string) {....raises: [SslError, OSError],
        tags: [WriteIOEffect], forbids: [].}

    proc ehlo(smtp: AsyncSmtp): Future[bool] {....stackTrace: false,
        raises: [Exception, ValueError, SslError], tags: [RootEffect], forbids: [].}

  Sends EHLO request.

    proc ehlo(smtp: Smtp): bool {....raises: [SslError, OSError, TimeoutError],
                                  tags: [WriteIOEffect, ReadIOEffect, TimeEffect],
                                  forbids: [].}

    proc helo(smtp: AsyncSmtp): owned(Future[void]) {....stackTrace: false,
        raises: [Exception, SslError, ValueError], tags: [RootEffect], forbids: [].}

    proc helo(smtp: Smtp) {....raises: [SslError, OSError, TimeoutError, ReplyError],
                            tags: [WriteIOEffect, ReadIOEffect, TimeEffect],
                            forbids: [].}

    proc newAsyncSmtp(useSsl = false; debug = false; sslContext: SslContext = nil): AsyncSmtp {.
        ...raises: [OSError, SslError, LibraryError, Exception, IOError],
        tags: [RootEffect, ReadDirEffect, ReadEnvEffect], forbids: [].}

  Creates a new `AsyncSmtp` instance.

    proc newSmtp(useSsl = false; debug = false; sslContext: SslContext = nil): Smtp {.
        ...raises: [OSError, SslError, LibraryError, Exception, IOError],
        tags: [RootEffect, ReadDirEffect, ReadEnvEffect], forbids: [].}

  Creates a new `Smtp` instance.

    proc recipients(msg: Message): seq[Email] {....raises: [], tags: [], forbids: [].}

  Retrieves all recipients of the message, which are all recipients defined for to, cc and bcc

    proc sender(msg: Message): Email {....raises: [], tags: [], forbids: [].}

    proc sendMail(smtp: AsyncSmtp; fromAddr: string; toAddrs: seq[string];
                  msg: string): owned(Future[void]) {....stackTrace: false,
        raises: [Exception, SslError, ValueError], tags: [RootEffect], forbids: [].}

  Sends `msg` from `fromAddr` to the addresses specified in `toAddrs`. Messages may be formed using `createMessage` by converting the Message into a string.

  You need to make sure that `fromAddr` and `toAddrs` don't contain any newline characters. Failing to do so will raise `AssertionDefect`.

    proc sendMail(smtp: AsyncSmtp; msg: Message): owned(Future[void]) {.
        ...stackTrace: false, raises: [Exception, SslError, ValueError],
        tags: [RootEffect], forbids: [].}

  Convenience utility for sending messages. Sends `msg` from the sender as specified in sender and the recipients as specified in recipients.

  See also:

  - sendMail

    proc sendMail(smtp: Smtp; fromAddr: string; toAddrs: seq[string]; msg: string) {.
        ...raises: [SslError, OSError, TimeoutError, ReplyError],
        tags: [WriteIOEffect, ReadIOEffect, TimeEffect], forbids: [].}

    proc sendMail(smtp: Smtp; msg: Message) {.
        ...raises: [SslError, OSError, TimeoutError, ReplyError],
        tags: [WriteIOEffect, ReadIOEffect, TimeEffect], forbids: [].}

    proc startTls(smtp: AsyncSmtp; sslContext: SslContext = nil): owned(
        Future[void]) {....stackTrace: false, raises: [Exception, SslError, ValueError,
        LibraryError, IOError], tags: [RootEffect, ReadDirEffect, ReadEnvEffect],
                        forbids: [].}

  Put the SMTP connection in TLS (Transport Layer Security) mode. May fail with ReplyError

    proc startTls(smtp: Smtp; sslContext: SslContext = nil) {....raises: [SslError,
        OSError, TimeoutError, ReplyError, Exception, LibraryError, IOError], tags: [
        WriteIOEffect, ReadIOEffect, TimeEffect, RootEffect, ReadDirEffect,
        ReadEnvEffect], forbids: [].}