Packages

email

Compose email with recipients, HTML bodies and attachments, check it, and send it through an SMTP server.

import "std:email"

std:email builds an email message and sends it through an SMTP server. Composing needs no network, so you can build, check and print a message to see exactly what would go out. Only send talks to a server.

Build a message#

email.new(options) returns a result, because it checks every address. Add recipients, set a body, and read the pieces back:

main.osl
import "std:email"

auto mail = email.new({from: "ada@example.com", to: "bob@example.com", subject: "Lunch?"}).unwrap()
mail.setBody("Hi Bob,\nare you free at noon?")

log mail.from() mail.to() mail.subject()
log mail.preview()
Click the code to edit it

preview() is a quick look for logs and tests.

More recipients#

addTo, addCc and addBcc add one address each, and setTo and friends replace the lot. Bcc addresses get the message but never appear in the headers:

main.osl
import "std:email"

auto mail = email.new({from: "ada@example.com", to: ["bob@example.com", "cy@example.com"]}).unwrap()
mail.addCc("dee@example.com").unwrap()
mail.addBcc("boss@example.com").unwrap()

log mail.recipients()
log mail.bcc()
log mail.hasRecipient("boss@example.com")
log mail.stringify().contains("boss@example.com")
Click the code to edit it

Bad addresses#

Adding a bad address fails and leaves the message as it was:

main.osl
import "std:email"

auto mail = email.new({from: "ada@example.com"}).unwrap()

auto bad = mail.addTo("not an address")
log bad.isErr() bad.unwrapErr().kind
log mail.to()

log email.new({from: "nope"}).isErr()
Click the code to edit it

Check before sending#

validate() says whether the message can be sent: it needs a sender, a recipient and a subject, and it explains what is missing:

main.osl
import "std:email"

auto mail = email.new({to: "bob@example.com"}).unwrap()
log mail.validate().unwrapErr().message

mail.setFrom("ada@example.com").unwrap()
log mail.validate().unwrapErr().message

mail.setSubject("Hi")
mail.setBody("hello")
log mail.validate().isOk()
Click the code to edit it

HTML and attachments#

setBody(text, {html: true}) sends the body as HTML. attach(name, data) adds a file from memory and attachFile(path) one from disk:

main.osl
import "std:email"

auto mail = email.new({from: "ada@example.com", to: "bob@example.com", subject: "Report"}).unwrap()
mail.setBody("<h1>Weekly report</h1><p>See attached.</p>", {html: true})
mail.attach("numbers.csv", "week,sales\n1,10\n2,14\n").unwrap()

log mail.isHTML()
log mail.attachments()
string wire = mail.stringify()
log wire.contains("Content-Type: text/html")
log wire.contains("numbers.csv")
Click the code to edit it

stringify() returns the complete message as send would transmit it, which is useful for tests that check what an app would email.

Quick check

Which recipients appear in the message's headers?

Sending#

mail.send(host, options) delivers the message. The defaults suit a normal provider: port 587 with TLS negotiated when the server offers it. Credentials go in the options:

main.osl
import "std:email"
import "std:env"

auto mail = email.new({from: "ada@example.com", to: "bob@example.com", subject: "Hi"}).unwrap()
mail.setBody("Sent from OSL")

auto outcome = mail.send("smtp.example.com", {
  username: env.get("SMTP_USER"),
  password: env.get("SMTP_PASSWORD")
})
switch outcome (
  case ok(_)
    log "sent"
  case err(e)
    log "not sent:" e.kind e.message
)
Click the code to edit it

Failures come back as an error: NetworkError and TimeoutError for connection trouble, PermissionError for a refused login, UnsupportedError when the server has no TLS and you gave a password (the password would travel in the clear), RuntimeError when the server refuses the sender, recipient or message, and StateError when the message isn't valid. Read the password from env, not from source.

Your turn

A receipt

Build a message from shop@example.com to a customer with the subject Your receipt and a body of Total: 12.50. Print its subject, and whether it is valid.

main.osl
Ctrl Enter runs
Expected output
Your receipt
true

API reference#

91 members, generated from the std:email source of OSL 9.3.0.

Functions

#email.addBcc(any recipient) boolean

Deprecated. Deprecated: use email.new() and message.addBcc(address) instead.

addBcc adds a Bcc address to the shared message.

#email.addCc(any recipient) boolean

Deprecated. Deprecated: use email.new() and message.addCc(address) instead.

addCc adds a Cc address to the shared message.

#email.addTo(any recipient) boolean

Deprecated. Deprecated: use email.new() and message.addTo(address) instead.

addTo adds a To address to the shared message.

#email.addToMany(array recipients) boolean

Deprecated. Deprecated: use email.new({to: addresses}) instead.

addToMany adds To addresses to the shared message.

#email.attachContent(object files) boolean

Deprecated. Deprecated: use email.new() and message.attach(name, data) instead.

attachContent attaches name → content pairs to the shared message.

#email.attachFile(any filePath) boolean

Deprecated. Deprecated: use email.new() and message.attachFile(path) instead.

attachFile attaches a file to the shared message.

#email.buildMessage(string from, any ...unused) string

Deprecated. Deprecated: use message.stringify() instead.

buildMessage returns the shared message's text as sent by from.

#email.clear()

Deprecated. Deprecated: use message.clear() instead.

clear empties the shared message except its sender.

#email.create() *email.Email

Deprecated. Deprecated: use email.new(options?) instead.

create returns a new, empty message.

#email.fromMap(object data) *email.Email

Deprecated. Deprecated: use email.new(options) instead, which fails with ValueError for an invalid address.

fromMap builds a message from {from, to, cc, bcc, subject, body, html}, silently skipping invalid addresses.

#email.getBcc() array

Deprecated. Deprecated: use email.new() and message.bcc() instead.

getBcc returns the shared message's Bcc addresses.

#email.getBody() string

Deprecated. Deprecated: use email.new() and message.body() instead.

getBody returns the shared message's body.

#email.getCc() array

Deprecated. Deprecated: use email.new() and message.cc() instead.

getCc returns the shared message's Cc addresses.

#email.getHeaders() string[string]

Deprecated. Deprecated: use message.headers() instead.

getHeaders returns the shared message's From, To, Subject and Date.

#email.getRecipientCount() int

Deprecated. Deprecated: use message.recipients().len instead.

getRecipientCount returns the shared message's number of recipients.

#email.getRecipients() array

Deprecated. Deprecated: use message.recipients() instead.

getRecipients returns the shared message's recipients.

#email.getSubject() string

Deprecated. Deprecated: use email.new() and message.subject() instead.

getSubject returns the shared message's subject.

#email.getTo() array

Deprecated. Deprecated: use email.new() and message.to() instead.

getTo returns the shared message's To addresses.

#email.hasRecipient(string recipient) boolean

Deprecated. Deprecated: use message.hasRecipient(address) instead.

hasRecipient reports whether the shared message has the recipient.

#email.isHTML() boolean

Deprecated. Deprecated: use email.new() and message.isHTML() instead.

isHTML reports whether the shared message's body is HTML.

#email.new(object? options) result<*email.Email, error>

new returns a message. Options: from, to, cc and bcc (an address or an array of addresses), subject, body and html (true when body is HTML). Fails with ValueError when an address is invalid; addresses must be plain ASCII such as "name@example.com".

#email.preview() string

Deprecated. Deprecated: use message.preview() instead.

preview summarises the shared message.

#email.queue() object

Deprecated. Deprecated: use message.toMap() instead.

queue returns {email, queuedAt, sent: false} for the shared message.

#email.reset()

Deprecated. Deprecated: use message.reset() instead.

reset empties the shared message.

#email.sendGmail(any username, any password) object

Deprecated. Deprecated: use message.send("smtp.gmail.com", {username, password}) instead.

sendGmail sends the shared message through Gmail.

#email.sendLocalhost() object

Deprecated. Deprecated: use message.send("localhost", {port: 25}) instead.

sendLocalhost sends the shared message through localhost:25.

#email.sendOffice365(any username, any password) object

Deprecated. Deprecated: use message.send("smtp.office365.com", {username, password}) instead.

sendOffice365 sends the shared message through Office 365.

#email.sendOutlook(any username, any password) object

Deprecated. Deprecated: use message.send("smtp-mail.outlook.com", {username, password}) instead.

sendOutlook sends the shared message through Outlook.

#email.sendWithSmtp(any host, any port, any username, any ...rest) object

Deprecated. Deprecated: use email.new() and message.send(host, options) instead.

sendWithSmtp(host, port, username, password, auth) sends the shared message.

#email.setBcc(any recipients) boolean

Deprecated. Deprecated: use email.new() and message.setBcc(addresses) instead.

setBcc replaces the shared message's Bcc addresses, skipping invalid ones.

#email.setBody(any body)

Deprecated. Deprecated: use email.new({body}) instead.

setBody sets the shared message's body.

#email.setCc(any recipients) boolean

Deprecated. Deprecated: use email.new() and message.setCc(addresses) instead.

setCc replaces the shared message's Cc addresses, skipping invalid ones.

#email.setFrom(any addr) boolean

Deprecated. Deprecated: use email.new({from}) and message.setFrom(address) instead.

setFrom sets the shared message's sender, or returns false for an invalid address.

#email.setHTML(any html) boolean

Deprecated. Deprecated: use email.new({body, html: true}) instead.

setHTML sets an HTML body on the shared message and returns true.

#email.setSubject(any subject)

Deprecated. Deprecated: use email.new({subject}) instead.

setSubject sets the shared message's subject.

#email.setText(any text)

Deprecated. Deprecated: use email.new({body}) instead.

setText sets a plain-text body on the shared message.

#email.setTo(any recipients) boolean

Deprecated. Deprecated: use email.new() and message.setTo(addresses) instead.

setTo replaces the shared message's To addresses.

#email.toMap() object

Deprecated. Deprecated: use message.toMap() instead.

toMap returns the shared message as an object.

#email.validate() boolean

Deprecated. Deprecated: use message.validate() instead.

validate reports whether the shared message has a sender, a To address and a subject.

#email.wrapText(any width) boolean

Deprecated. Deprecated: use message.setBody(text, {wrap: width}) instead.

wrapText wraps the shared message's body.

*email.Email

#email.addBcc(string address) result<unit, error>

addBcc adds a Bcc address, like addTo.

#email.addCc(string address) result<unit, error>

addCc adds a Cc address, like addTo.

#email.addTo(string address) result<unit, error>

addTo adds a To address. An address already on the message (in any list, ignoring case) is skipped. Fails with ValueError when address is invalid.

#email.addToMany(array recipients) boolean

Deprecated. Deprecated: use message.addTo(address) for each address instead.

addToMany adds To addresses, stopping with false at the first invalid or duplicate one.

#email.attach(string name, any data) result<unit, error>

attach adds an attachment called name holding data, a string or byte[]. Fails with ValueError when name is empty or the message already has an attachment with that name. Throws TypeError for other data types.

#email.attachContent(object files) boolean

Deprecated. Deprecated: use message.attach(name, data) instead.

attachContent attaches each name → content pair of files, returning false at the first empty or duplicate name.

#email.attachFile(string path, object? options) result<unit, error>

attachFile attaches the file at path, named after the file. Options: name (the attachment's name instead). Fails with NotFoundError or PermissionError when the file can't be read, IOError when path is a directory, and ValueError when an attachment with that name exists.

#email.attachments() string[]

attachments returns the attachment names, sorted.

#email.bcc() string[]

bcc returns the Bcc addresses. They receive the message but are never written into it.

#email.body() string

body returns the body text.

#email.buildMessage(string from, any ...unused) string

Deprecated. Deprecated: use message.stringify() instead.

buildMessage returns the message text as sent by from.

#email.cc() string[]

cc returns the Cc addresses.

#email.clear()

clear removes the recipients, subject, body and attachments, keeping the sender.

#email.create() *email.Email

Deprecated. Deprecated: use email.new(options?) instead.

create returns a new, empty message.

#email.from() string?

from returns the sender's address, or null when none is set.

#email.fromMap(object data) *email.Email

Deprecated. Deprecated: use email.new(options) instead.

fromMap builds a new message from {from, to, cc, bcc, subject, body, html}, silently skipping invalid addresses.

#email.getBcc() array

Deprecated. Deprecated: use message.bcc() instead.

getBcc returns the Bcc addresses.

#email.getBody() string

Deprecated. Deprecated: use message.body() instead.

getBody returns the body.

#email.getCc() array

Deprecated. Deprecated: use message.cc() instead.

getCc returns the Cc addresses.

#email.getHeaders() string[string]

Deprecated. Deprecated: use message.headers() instead.

getHeaders returns From, To, Subject and Date.

#email.getRecipientCount() int

Deprecated. Deprecated: use message.recipients().len instead.

getRecipientCount returns the number of recipients.

#email.getRecipients() array

Deprecated. Deprecated: use message.recipients() instead.

getRecipients returns every recipient.

#email.getSubject() string

Deprecated. Deprecated: use message.subject() instead.

getSubject returns the subject.

#email.getTo() array

Deprecated. Deprecated: use message.to() instead.

getTo returns the To addresses.

#email.hasRecipient(string address) boolean

hasRecipient reports whether address is a To, Cc or Bcc recipient, ignoring case.

#email.headers() string[string]

headers returns the headers the message is sent with: From, To, Cc (when there are Cc addresses), Subject, Date (now) and MIME-Version. Bcc addresses are never included.

#email.isHTML() boolean

isHTML reports whether the body is sent as HTML rather than plain text.

#email.preview() string

preview returns a short readable summary: the From, To and Subject lines, a blank line and the body.

#email.queue() object

Deprecated. Deprecated: use message.toMap() instead.

queue returns {email, queuedAt (unix seconds), sent: false}. Nothing is queued.

#email.recipients() string[]

recipients returns every To, Cc and Bcc address, in that order.

#email.reset()

reset clears everything, the sender included.

#email.send(string host, object? options) result<unit, error>

send delivers the message through the SMTP server at host. Options: port (default 587, or 465 with implicit TLS), username, password, tls ("auto", "starttls", "implicit" or "none") and timeout (milliseconds, default 30000). Fails with StateError, PermissionError, UnsupportedError, NetworkError, TimeoutError or RuntimeError.

#email.sendGmail(any username, any password) object

Deprecated. Deprecated: use message.send("smtp.gmail.com", {username, password}) instead.

sendGmail sends through smtp.gmail.com:587.

#email.sendLocalhost() object

Deprecated. Deprecated: use message.send("localhost", {port: 25}) instead.

sendLocalhost sends through localhost:25 without signing in.

#email.sendOffice365(any username, any password) object

Deprecated. Deprecated: use message.send("smtp.office365.com", {username, password}) instead.

sendOffice365 sends through smtp.office365.com:587.

#email.sendOutlook(any username, any password) object

Deprecated. Deprecated: use message.send("smtp-mail.outlook.com", {username, password}) instead.

sendOutlook sends through smtp-mail.outlook.com:587.

#email.sendWithSmtp(any host, any port, any username, any ...rest) object

Deprecated. Deprecated: use message.send(host, {port, username, password}) instead, which fails with a typed error.

sendWithSmtp(host, port, username, password, auth) sends the message and returns {success: true, message} or {success: false, error}.

#email.setBcc(array addresses) result<unit, error>

setBcc replaces the Bcc addresses, like setTo.

#email.setBody(string body, object? options)

setBody replaces the body. Options: html (true for an HTML body, false for plain text; when omitted the format stays as it was, plain text for a new message) and wrap (wrap each line at this many characters, breaking between words). Throws ValueError when wrap is less than 1.

#email.setCc(array addresses) result<unit, error>

setCc replaces the Cc addresses, like setTo.

#email.setFrom(string address) result<unit, error>

setFrom sets the sender's address. Fails with ValueError, leaving the sender unchanged, when address isn't a valid email address.

#email.setHTML(any html) boolean

Deprecated. Deprecated: use message.setBody(html, {html: true}) instead.

setHTML sets an HTML body and returns true.

#email.setSubject(string subject)

setSubject sets the subject. Line breaks become spaces, so a subject can't add headers.

#email.setText(any text)

Deprecated. Deprecated: use message.setBody(text, {html: false}) instead.

setText sets a plain-text body.

#email.setTo(array addresses) result<unit, error>

setTo replaces the To addresses with addresses, an array of strings; addresses already on the message are skipped. Fails with ValueError, changing nothing, when any address is invalid.

#email.stringify() string

stringify returns the message exactly as send would transmit it: MIME headers, a quoted-printable body and base64 attachments. Bcc addresses are not included.

#email.subject() string

subject returns the subject.

#email.to() string[]

to returns the To addresses.

#email.toMap() {bcc: string[], body: string, cc: string[], from: string, html: boolean, subject: string, to: string[]}

toMap returns the message as an object with the keys from, to, cc, bcc, subject, body and html. Attachments are not included. email.new accepts the same keys.

#email.validate() result<unit, error>

validate checks that the message can be sent: it has a sender, at least one To address and a subject. Fails with StateError naming what is missing.

#email.wrapText(any width) boolean

Deprecated. Deprecated: use message.setBody(text, {wrap: width}) instead.

wrapText wraps the body at width characters (78 when width is 0) and returns true.