~/bend-docscommunity

send.bend relies on unsafe/foreign

raw source on the hub · import 0x650cd729029c76d9f6151ee977dc0ae8/send.bend as Send

Send mail over SMTP.

bend send.bend -o send SMTP_PASSWORD=... ./send --host smtp.example.com --user me@example.com \ --from "Me <me@example.com>" --to "Ana <ana@x.com>, bia@y.com" \ --cc c@z.com --bcc d@w.com --subject "Oi" --body "texto" \ --html-file corpo.html --attach relatorio.pdf --attach foto.jpg \ --header "X-Campaign: outubro"

Address lists take "Name <addr>" or "addr", comma-separated (quote a name with a comma: "\"Silva, Ana\" <ana@x.com>"). --attach and --header repeat. --individually sends one message per --to address, each seeing only itself, all over one connection. --debug prints the dialog on stderr, with secrets and the message's text left out. --tls starttls (default; port 587), tls (implicit; port 465) or plain (port 25); --port overrides. --auth plain, login, xoauth2 or oauthbearer (default: picked from what the server offers). Secrets come only from the environment: SMTP_PASSWORD, or SMTP_OAUTH_TOKEN (an OAuth 2 access token). --cafile trusts that CA instead of the system's; --helo names this host.

Exit: 0 sent to everyone; 3 sent in part (a refused recipient, or some of the messages); 1 nothing sent; 2 bad usage.

5 imports
import Base
import ./core.bend as C
import ./smtp.bend as S
import ./addr.bend as A
import ./mime.bend as M

Types

type Opt source · line 34 · raw

Data

An option and its value, as given.

type Rep source · line 327 · raw

Data

What to print and the exit code: how many messages went and how many did not, and a line (or more) for each.

Definitions

def Args.valued source · line 38 · raw

List<&2, String>

The options that take a value, and the ones that stand alone.

def Args.alone source · line 45 · raw

List<&2, String>

def Args.is source · line 49 · raw

@ks:List<&2, String> -> @k:String -> Bool

def Args.yes source · line 52 · raw

@add:Bool -> @rest:List<&2, String> -> List<&2, String>

def Args.pair source · line 61 · raw

@xs:List<&2, String> -> @+val:Bool -> List<&2, String>

The arguments with a "yes" after each option that stands alone, so they all come in pairs; val: this one is a value, not an option.

def Args.opts source · line 69 · raw

@xs:List<&2, String> -> List<&2, Opt>

def Args.copy source · line 79 · raw

@xs:List<&1, String> -> List<&2, String>

The command line as a reusable list (its head is the program itself).

def Args.parse source · line 86 · raw

@xs:List<&2, String> -> List<&2, Opt>

def Args.get.go source · line 89 · raw

@os:List<&2, Opt> -> @+k:String -> @found:String -> String

def Args.get source · line 98 · raw

@os:List<&2, Opt> -> @+k:String -> String

An option's value (the last one given), or "".

def Args.keep source · line 101 · raw

@yes:Bool -> @v:String -> @rest:List<&2, String> -> List<&2, String>

def Args.all source · line 109 · raw

@os:List<&2, Opt> -> @+k:String -> List<&2, String>

Every value given for an option, in order.

def Args.on source · line 117 · raw

@os:List<&2, Opt> -> @k:String -> Bool

def Args.bad source · line 121 · raw

@os:List<&2, Opt> -> String

The first option that does not exist, or lacks its value; "" if none.

def Send.mode source · line 134 · raw

@+tls:String -> @+port:String -> 0x650cd729029c76d9f6151ee977dc0ae8/core.Mode

def Send.auth source · line 140 · raw

@+a:String -> 0x650cd729029c76d9f6151ee977dc0ae8/core.Auth

def Send.port.or source · line 147 · raw

@m:Maybe<&2, U32> -> @+dflt:U32 -> U32

def Send.port.dflt source · line 154 · raw

@mode:0x650cd729029c76d9f6151ee977dc0ae8/core.Mode -> U32

def Send.both source · line 163 · raw

@+os:List<&2, Opt> -> @a:String -> @b:String -> Bool

def Send.notify.words source · line 166 · raw

@ws:List<&2, String> -> Bool

def Send.notify.ok source · line 175 · raw

@+ws:List<&2, String> -> Bool

NOTIFY's values (RFC 3461 4.1): never alone, or any of the others.

def Send.some source · line 179 · raw

@+os:List<&2, Opt> -> @ks:List<&2, String> -> Bool

def Send.every source · line 186 · raw

@+os:List<&2, Opt> -> @ks:List<&2, String> -> Bool

def Send.problem source · line 194 · raw

@+os:List<&2, Opt> -> String

What is wrong with the options, or "".

def Send.more source · line 237 · raw

@+os:List<&2, Opt> -> @ks:List<&2, String> -> List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/core.Kv>

The named options of S.Opts, from the flags of the same names.

def Send.opts source · line 244 · raw

@+os:List<&2, Opt> -> @pass:String -> @token:String -> 0x650cd729029c76d9f6151ee977dc0ae8/core.Opts

def Send.header.of source · line 257 · raw

@parts:List<&2, String> -> 0x650cd729029c76d9f6151ee977dc0ae8/core.Hdr

"Name: value" as a header; a line with no ":" has no name, and is refused later.

def Send.headers source · line 264 · raw

@hs:List<&2, String> -> List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/core.Hdr>

def Send.mail source · line 272 · raw

@+os:List<&2, Opt> -> @text:String -> @html:String -> @files:List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/mime.Part> -> 0x650cd729029c76d9f6151ee977dc0ae8/core.Mail

The message as the options describe it.

def Send.only source · line 280 · raw

@m:0x650cd729029c76d9f6151ee977dc0ae8/core.Mail -> @t:0x650cd729029c76d9f6151ee977dc0ae8/addr.Mbox -> 0x650cd729029c76d9f6151ee977dc0ae8/core.Mail

m with t as its only To.

def Send.alone source · line 284 · raw

@+m:0x650cd729029c76d9f6151ee977dc0ae8/core.Mail -> @to:List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/addr.Mbox> -> List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/core.Mail>

def Send.to source · line 291 · raw

@m:0x650cd729029c76d9f6151ee977dc0ae8/core.Mail -> List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/addr.Mbox>

def Send.mails.at source · line 295 · raw

@each:Bool -> @+m:0x650cd729029c76d9f6151ee977dc0ae8/core.Mail -> List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/core.Mail>

def Send.mails source · line 304 · raw

@+os:List<&2, Opt> -> @m:0x650cd729029c76d9f6151ee977dc0ae8/core.Mail -> List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/core.Mail>

The messages to send: the one described, or, with --individually, a copy of it for each --to address.

def Send.creds source · line 309 · raw

@+user:String -> @+auth:String -> @+pass:String -> @+token:String -> String

What is missing for AUTH, or "": a password for PLAIN and LOGIN, a token for the OAuth mechanisms, one of the two otherwise.

def Rep.lines source · line 330 · raw

@xs:List<&2, String> -> String

def Rep.to source · line 338 · raw

@+label:String -> String

" to <label>" when the messages are told apart, else nothing.

def Rep.refused source · line 341 · raw

@+bad:List<&2, String> -> String

def Rep.one source · line 346 · raw

@+label:String -> @x:0x650cd729029c76d9f6151ee977dc0ae8/core.Sent -> Pair(Bool, String)

One message's line, and whether it went.

def Rep.add source · line 353 · raw

@r:Rep -> @l:Pair(Bool, String) -> Rep

def Rep.each source · line 360 · raw

@xs:List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/core.Sent> -> @ls:List<&2, String> -> @r:Rep -> Rep

The messages tried, each with its label.

def Rep.fatal source · line 370 · raw

@r:Rep -> @+code:U32 -> @+error:String -> @+left:U32 -> Rep

The error that ended the connection, and the messages it left untried.

def Rep.of source · line 379 · raw

@+labels:List<&2, String> -> @b:0x650cd729029c76d9f6151ee977dc0ae8/core.Batch -> Rep

The report of a connection; labels name the messages ([""] for one).

def Rep.exit source · line 386 · raw

@r:Rep -> U32

0 when every message went to everyone, 1 when none went, else 3.

def Rep.text source · line 392 · raw

@r:Rep -> String

def Send.say source · line 399 · raw

@ok:Bool -> @code:U32 -> @text:String -> IO(Unit)

def Send.report source · line 406 · raw

@+r:Rep -> IO(Unit)

def Send.env.or source · line 410 · raw

@r:Result<&1, &1, Pair(U32, String), String> -> String

def Send.env source · line 417 · raw

@name:String -> IO(String)

def Send.read source · line 422 · raw

@m:Pair(File, Result<&1, &1, Pair(U32, String), String>) -> IO(String)

def Send.text.at source · line 428 · raw

@none:Bool -> @file:String -> @text:String -> IO(String)

def Send.text source · line 439 · raw

@+file:String -> @text:String -> IO(String)

A text from its file (up to 16 MiB), else as given.

def Send.base.of source · line 442 · raw

@m:Maybe<&2, String> -> String

def Send.base source · line 450 · raw

@path:String -> String

A path's last part, the file's name.

def Send.got source · line 453 · raw

@m:Pair(File, Result<&1, &1, Pair(U32, String), List<&2, U32>>) -> @+path:String -> IO(0x650cd729029c76d9f6151ee977dc0ae8/mime.Part)

def Send.file source · line 463 · raw

@+path:String -> IO(0x650cd729029c76d9f6151ee977dc0ae8/mime.Part)

One attachment: its bytes (up to 25 MiB), name and type.

def Send.files source · line 470 · raw

@ps:List<&2, String> -> IO(List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/mime.Part>)

def Send.labels.more source · line 480 · raw

@ms:List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/core.Mail> -> List<&2, String>

def Send.labels source · line 489 · raw

@ms:List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/core.Mail> -> List<&2, String>

The labels that tell the messages apart: each one's --to address, or one empty label for a single message.

def Send.all source · line 498 · raw

@+o:0x650cd729029c76d9f6151ee977dc0ae8/core.Opts -> @+ms:List<&2, 0x650cd729029c76d9f6151ee977dc0ae8/core.Mail> -> IO(Unit)

def Send.go source · line 503 · raw

@+os:List<&2, Opt> -> @pass:String -> @token:String -> IO(Unit)

def Send.usage source · line 511 · raw

String

def Send.creds.ok source · line 525 · raw

@problem:String -> @+os:List<&2, Opt> -> @pass:String -> @token:String -> IO(Unit)

def Send.secrets source · line 533 · raw

@+os:List<&2, Opt> -> @+pass:String -> @+token:String -> IO(Unit)

def Send.start source · line 537 · raw

@+os:List<&2, Opt> -> IO(Unit)

def Send.run source · line 543 · raw

@problem:String -> @+os:List<&2, Opt> -> IO(Unit)

def Send.args source · line 550 · raw

@+os:List<&2, Opt> -> IO(Unit)

def main source · line 553 · raw

IO(Unit)