Liking cljdoc? Tell your friends :D

dev.arkaitz.sendmail-base

Email for an application: build a mailer from configuration once, then send! a message with it.

(def mailer (mail/mailer {:transport :console :from "noreply@example.com"}))
(mail/send! mailer {:to "ada@example.com" :subject "Hello" :text "…"})

Two transports, chosen by :transport:

  • :console prints the whole message — headers and body — to *out* and sends nothing. It is for development, where a sign-in link should be readable in the terminal: in production it would put credentials in the logs, which the host refuses (this library cannot know what production is).
  • :smtp delivers through a submission server with this library's own client (dev.arkaitz.sendmail-base.smtp, SPEC §5): TLS always, a required wall-clock deadline on every send, and refusals that never echo a recipient, a server's text or a password.

A mailer is a value. It holds no connection and no thread: every send! connects, delivers one message and closes, inside its deadline.

Email for an application: build a mailer from configuration once, then `send!` a
message with it.

    (def mailer (mail/mailer {:transport :console :from "noreply@example.com"}))
    (mail/send! mailer {:to "ada@example.com" :subject "Hello" :text "…"})

Two transports, chosen by `:transport`:
- `:console` prints the whole message — headers and body — to `*out*` and sends
  nothing. It is for development, where a sign-in link should be readable in the
  terminal: in production it would put credentials in the logs, which the host
  refuses (this library cannot know what production is).
- `:smtp` delivers through a submission server with this library's own client
  (`dev.arkaitz.sendmail-base.smtp`, SPEC §5): TLS always, a required wall-clock
  deadline on every send, and refusals that never echo a recipient, a server's text
  or a password.

A mailer is a value. It holds no connection and no thread: every `send!` connects,
delivers one message and closes, inside its deadline.
raw docstring

dev.arkaitz.sendmail-base.integrant

Optional: requiring this namespace installs one Integrant key, :dev.arkaitz.sendmail-base/mailer, whose value is (mailer config). There is no halt-key!: a mailer holds no connection and no thread, so there is nothing to close.

{:dev.arkaitz.sendmail-base/mailer {:transport :smtp :host "smtp.example.com"
                                    :port 587 :tls :starttls
                                    :user "app" :password #wb/env "SMTP_PASSWORD"
                                    :from "noreply@example.com" :deadline-ms 10000}}

A refusal names its key and never the value; but Integrant's own failure carries the whole resolved configuration of the key that threw, password included, so a host logs the cause and never the exception Integrant threw.

Optional: requiring this namespace installs one Integrant key,
`:dev.arkaitz.sendmail-base/mailer`, whose value is `(mailer config)`. There is no
`halt-key!`: a mailer holds no connection and no thread, so there is nothing to
close.

    {:dev.arkaitz.sendmail-base/mailer {:transport :smtp :host "smtp.example.com"
                                        :port 587 :tls :starttls
                                        :user "app" :password #wb/env "SMTP_PASSWORD"
                                        :from "noreply@example.com" :deadline-ms 10000}}

A refusal names its key and never the value; but Integrant's own failure carries the
whole resolved configuration of the key that threw, password included, so a host
logs the cause and never the exception Integrant threw.
raw docstring

No vars found in this namespace.

dev.arkaitz.sendmail-base.smtp

The SMTP submission client: one message per connection, over TLS, inside one wall-clock deadline (SPEC §5).

The deadline is a watchdog, not a timeout per call. A virtual thread closes the socket when the deadline passes, which makes whatever is blocked — the connect, the TLS handshake, a read, a write — throw at once. A timeout per read would let a server that drips one byte at a time hold a send for ever; a socket write has no timeout at all. Name resolution, which no socket bounds, runs on a thread of its own and is waited for only until the deadline.

What a failure says. The stage it happened at and the server's reply code — refused at RCPT with 550 — and never the recipient, the server's own text, the message or a password: the caller logs what it is given (auth-base logs a delivery failure whole), and a reply such as 550 <ada@…> unknown carries the address.

The SMTP submission client: one message per connection, over TLS, inside one
wall-clock deadline (SPEC §5).

**The deadline is a watchdog, not a timeout per call.** A virtual thread closes the
socket when the deadline passes, which makes whatever is blocked — the connect, the
TLS handshake, a read, a write — throw at once. A timeout per read would let a
server that drips one byte at a time hold a send for ever; a socket write has no
timeout at all. Name resolution, which no socket bounds, runs on a thread of its own
and is waited for only until the deadline.

**What a failure says.** The stage it happened at and the server's reply code —
`refused at RCPT with 550` — and never the recipient, the server's own text, the
message or a password: the caller logs what it is given (auth-base logs a delivery
failure whole), and a reply such as `550 <ada@…> unknown` carries the address.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close