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.
Opt@key:String -> @val:String -> Opt
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.
Rep@ok:U32 -> @bad:U32 -> @text:String -> Rep
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)