IMAP & POP3
NEW EMAIL IMAP and NEW EMAIL POP3 connect and authenticate to a mailbox, captured with SET. Every subsequent operation is subject-first — EMAIL ?conn VERB .... This is a separate, dedicated verb family from MAIL, which only sends outbound email — see Mail & Redirection.
Where the Mail Arrives
A mailbox needs the domain’s mail to be delivered here, and that is a DNS question rather than an OcaltQL one. There are three ways to arrange it, and which you pick decides how much of the domain Ocalt is responsible for.
Route 1 - Delegation: nothing to configure
Set the domain’s nameservers at your registrar to dns1.ocalt.com and dns2.ocalt.com. Ocalt serves the whole zone, and the moment a mailbox exists it writes the mail records itself - MX, SPF and DMARC included. There is nothing for you to add and nothing to keep in step.
This is the route to take unless you have a reason not to. See Custom Domains.
Route 2 - An A record: web and mail both here
Point the domain at 41.61.20.37 with an A record on @, then add the three mail records below yourself. You keep the zone, so anything else you run on the domain is untouched, but every record is yours to maintain.
Route 3 - Mail records only: the site stays where it is
If the website lives with another host and you only want the mailboxes here, leave the A record pointing wherever it already points and add only the three mail records. Ocalt never sees the web traffic. Register it with DOMAIN "tld.com" FOR MAIL, which checks the MX rather than the address, because there is no site here to check.
DOMAIN "tld.com" FOR MAIL SET ?r
AFTER EMIT ?r("mail_only")
(* The web for tld.com stays with your existing host *)
AFTER NEW EMAIL ACCOUNT "hello" AT "tld.com" WITH PASSWORD "Password" SET ?acc
AFTER EMIT ?acc("address")
The three records
Routes 2 and 3 need the same three. Add them at whoever provides your DNS, exactly as written.
| Type | Name | Value |
|---|---|---|
MX |
@ |
mail.ocalt.com priority 10 |
TXT |
@ |
v=spf1 include:mail.ocalt.com ~all |
TXT |
_dmarc |
v=DMARC1; p=none; rua=mailto:you@tld.com |
TXT |
ocalt._domainkey |
Given to you by DOMAIN STATUS - a long v=DKIM1 value unique to your domain |
What each record does
MX is the only one that carries mail. It tells every sending server where to deliver anything addressed to your domain; mail.ocalt.com is the host that accepts it. The priority number only matters when there are several - lower is tried first - and with one record the value is arbitrary. Without an MX, mail to your domain bounces before it ever reaches us.
SPF is a public list of who may send as you. include:mail.ocalt.com means “the machine Ocalt sends your mail from is allowed to”. It points at one host rather than at everything under ocalt.com, so authorising Ocalt to send as you does not quietly authorise anything else that Ocalt itself uses. ~all ends it with “treat anything else as suspicious” rather than “reject it outright”, which is the safer setting while you are still moving things around. If you send from somewhere else too - a newsletter service, your own server - add their include to the same record. There must be exactly one SPF record on a domain; a second one invalidates both.
DMARC tells a receiver what to do when SPF disagrees. p=none asks them to do nothing and simply report, which is where to start: you find out what is being sent in your name before you begin blocking it. The rua address receives those reports. Once the reports look right, tighten to p=quarantine and later p=reject.
DKIM proves a message really came from you. Ocalt generates a signing key for your domain the moment you point it, and signs everything sent from an address on it. The public half is the record above, and until it is published a receiver has nothing to check the signature against.
The value is long and unique to your domain, so it is not printed here. Ask for it:
DOMAIN STATUS "tld.com" SET ?d
AFTER EMIT ?d("dkim_name") & " -> " & ?d("dkim_value")
AFTER EMIT "published: " & ?d("dkim_published")
Publish it as a TXT record at the name it gives you, then run the same script again - dkim_published turns true once it resolves. On a delegated domain there is nothing to do: Ocalt writes the record itself.
DOMAIN ... FOR MAIL refuses until it can actually see the record, and the refusal says so - it is not a failure, only an answer that arrived early.Creating a Mailbox
A mailbox does not have to come from somewhere else. NEW EMAIL ACCOUNT creates one on a subdomain you own, or on a domain already pointed at Ocalt with DOMAIN. Once created, every verb on this page manages it — the account is an ordinary IMAP/POP3 mailbox, reached with the same NEW EMAIL IMAP connection as any other host.
NEW EMAIL ACCOUNT "hello" AT "mysite.ocalt.site" WITH PASSWORD "Password" SET ?emailaccountobject
AFTER EMIT ?emailaccountobject("address")
NEW EMAIL ACCOUNT "sales" AT "tld.com" WITH PASSWORD "Password" SET ?acc
AFTER EMIT ?acc("address")
(* tld.com must already be pointed at Ocalt — see DOMAIN on the Site Mode page *)
?err("message") says which of the two it was.NEW EMAIL ACCOUNT "hello" AT "mysite.ocalt.site" WITH PASSWORD "Password" SET ?acc
AFTER NEW EMAIL IMAP ?acc("imap_host") WITH "Password" AS ?acc("address") SET ?conn
AFTER EMAIL ?conn INBOX SET ?inbox
AFTER COUNT ?inbox SET ?n
AFTER EMIT ?n & " messages"
| Field | Description |
|---|---|
address | The full address — hello@mysite.ocalt.site |
imap_host | Host to pass to NEW EMAIL IMAP |
pop3_host | Host to pass to NEW EMAIL POP3 |
IMAP - Connect
NEW EMAIL IMAP speaks the standard protocol, so it connects to any server that does - a company Exchange box, a mailbox at your web host, Fastmail, Zoho, a self-hosted Dovecot, or one you created here. Three things are needed: the host, the address, and that mailbox’s password.
NEW EMAIL IMAP "mail.yourcompany.com" WITH "your_password" AS "you@yourcompany.com" SET ?conn
AFTER EMAIL ?conn INBOX SET ?inbox
AFTER COUNT ?inbox SET ?n
AFTER EMIT ?n & " messages"
Nothing there is Ocalt-specific. A mailbox you create here is the same shape - NEW EMAIL ACCOUNT hands you the host to use, so you never have to look one up.
NEW EMAIL ACCOUNT "hello" AT "mysite.ocalt.site" WITH PASSWORD "Password" SET ?acc
AFTER NEW EMAIL IMAP ?acc("imap_host") WITH "Password" AS ?acc("address") SET ?conn
AFTER EMAIL ?conn INBOX SET ?inbox
AFTER COUNT ?inbox SET ?n
AFTER EMIT ?n
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
NEW EMAIL IMAP "imap.gmail.com" WITH "ya29.access_token" AS "user@gmail.com" PWTYPE "oauth2" SET ?conn
"plain" — the WITH value is sent as the account password (for Gmail this must be an App Password; Google no longer accepts regular account passwords over IMAP, POP3, or SMTP). With PWTYPE "oauth2" the WITH value is an OAuth2 access token, delivered via SASL XOAUTH2 on IMAP, POP3, and the derived SMTP transport alike. PWTYPE is accepted by both NEW EMAIL IMAP and NEW EMAIL POP3. A failed connection — wrong credentials, unreachable host, unknown PWTYPE — is a catchable E4001, as is every subsequent protocol failure on an EMAIL operation, so OR CATCH ERROR SET ?err receives ?err("code"), ?err("message"), and ?err("verb") — see Error Codes.IMAP — Folders
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn LIST FOLDERS SET ?folders
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn INBOX SET ?inbox
AFTER EMAIL ?conn SENT SET ?sent
AFTER EMAIL ?conn DRAFTS SET ?drafts
AFTER EMAIL ?conn SPAM SET ?spam
AFTER EMAIL ?conn TRASH SET ?trash
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn FOLDER "Custom Folder Name" SET ?custom
IMAP — Unread and Search
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn UNREAD SET ?new
AFTER COUNT ?new SET ?n
AFTER EMIT ?n & " unread"
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn SEARCH "FROM boss@company.com" SET ?msgs
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn FOLDER "Sent" SEARCH "client@site.com" SET ?results
IMAP — Fetching a Message
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn INBOX SET ?inbox
AFTER EMIT ?inbox(0)("uid")
AFTER EMAIL ?conn UID ?inbox(0)("uid") SET ?msg
AFTER EMIT ?msg("subject")
IMAP — Flags
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn INBOX SET ?inbox
AFTER EMAIL ?conn MARK ?inbox(0)("uid") AS READ
AFTER EMAIL ?conn MARK ?inbox(0)("uid") AS UNREAD
AFTER EMAIL ?conn MARK ?inbox(0)("uid") AS FLAGGED
AFTER EMAIL ?conn MARK ?inbox(0)("uid") AS UNFLAGGED
AFTER EMAIL ?conn MARK ?inbox(0)("uid") AS DELETED
IMAP — Move and Copy
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn INBOX SET ?inbox
AFTER EMAIL ?conn MOVE ?inbox(0)("uid") TO "Trash"
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn INBOX SET ?inbox
AFTER EMAIL ?conn COPY ?inbox(0)("uid") TO "Custom Folder Name"
IMAP — Labels (Gmail Extension)
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn INBOX SET ?inbox
AFTER EMAIL ?conn LABELS ?inbox(0)("uid") SET ?labels
AFTER EMAIL ?conn ADD LABEL ?inbox(0)("uid") AS "Important"
AFTER EMAIL ?conn REMOVE LABEL ?inbox(0)("uid") AS "Important"
IMAP — Drafts
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn SAVE DRAFT TO "recipient@example.ocalt.com" SUBJECT "Hello" BODY "message text"
IMAP — Close
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn CLOSE
POP3
POP3 has no folders and no server-side search — it operates on a flat, download-and-delete model. NEW EMAIL POP3 connects the same way as IMAP, but the available operations are LIST, UID, DELETE, and CLOSE.
NEW EMAIL POP3 "pop.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
NEW EMAIL POP3 "pop.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn LIST SET ?messages
POP3’s LIST only ever returns uid and size per message — the protocol does not expose subject, sender, date, or body until the full message is fetched by UID.
NEW EMAIL POP3 "pop.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn LIST SET ?messages
AFTER EMIT ?messages(0)("uid")
AFTER EMIT ?messages(0)("size")
AFTER EMAIL ?conn UID ?messages(0)("uid") SET ?msg
AFTER EMIT ?msg("subject")
AFTER EMIT ?msg("from")
AFTER EMIT ?msg("date")
AFTER EMIT ?msg("body")
NEW EMAIL POP3 "pop.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn LIST SET ?messages
AFTER EMAIL ?conn DELETE ?messages(0)("uid")
AFTER EMAIL ?conn CLOSE
Sending Email
EMAIL ?conn SEND shares the exact same modifier set as MAIL: TO, SUBJECT, BODY, CC, BCC, REPLY TO, HEADER, and ATTACH. All modifiers are optional and can appear in any order.
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn SEND TO "recipient@example.ocalt.com" SUBJECT "Hello!" BODY "This is the body"
AFTER EMAIL ?conn CLOSE
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn SEND TO "boss@site.com" CC "team@site.com" SUBJECT "report" BODY "message"
AFTER EMAIL ?conn SEND TO "boss@site.com" BCC "secret@site.com" SUBJECT "hidden copy" BODY "message"
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn SEND TO "support@site.com" SUBJECT "support" BODY "help needed" REPLY TO "user@site.com"
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn SEND TO "email@email.com" HEADER "From: blah@blah.com" SUBJECT "with header" BODY "hello"
Sending Attachments
An attachment is shared to a URL first with FILE SHARE, then passed to SEND via ATTACH. This works identically for a local file or anything already reachable at a web URL. ATTACH accepts a single value or an array of values for multiple attachments.
FILE SHARE "/root/invoice.pdf" SET ?url
AFTER NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn SEND TO "client@site.com" SUBJECT "Invoice" BODY "See attached" ATTACH ?url
AFTER EMAIL ?conn CLOSE
NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn SEND TO "client@site.com" SUBJECT "Report" BODY "See attached" ATTACH "https://example.ocalt.com/files/report.pdf"
AFTER EMAIL ?conn CLOSE
FILE SHARE "/root/invoice.pdf" SET ?url1
AFTER FILE SHARE "/root/receipt.pdf" SET ?url2
AFTER NEW ARRAY SET ?attachments
AFTER APPEND ?url1 TO ?attachments
AFTER APPEND ?url2 TO ?attachments
AFTER NEW EMAIL IMAP "imap.gmail.com" WITH "app_password" AS "user@gmail.com" SET ?conn
AFTER EMAIL ?conn SEND TO "client@site.com" SUBJECT "Invoice + Receipt" BODY "See attached" ATTACH ?attachments
AFTER EMAIL ?conn CLOSE
MAIL only sends outbound email, EMAIL connects to and manages a mailbox via IMAP or POP3. NEW EMAIL IMAP and NEW EMAIL POP3 both produce a ?conn subject passed to every subsequent operation. UIDs are always retrieved from a real prior fetch, never hardcoded. SENT, DRAFTS, SPAM, and TRASH are bare keywords; any other folder uses FOLDER "name". EMAIL ... SEND shares the complete MAIL modifier set. POP3 is intentionally more limited than IMAP — no folders, no server-side search, no flags, no labels.