Documentation
¶
Overview ¶
Package skymail pkg/skymail/limits.go c4-app-mail
Package skymail pkg/skymail/mailbox.go c4-app-mail
Package skymail pkg/skymail/maildir.go c4-app-mail
Package skymail is a mailbox a visor hosts for its own PK: mail to <anything>@<base32-pk>.skynet (or .dmsg) arrives over plain SMTP on port 25, is stamped with the sender's authenticated PK, and is kept verbatim in a Maildir. Nothing about it needs a certificate, a domain or a public address, so it runs as well in a browser tab as on a server. The SMTP protocol loop and the relay are shared with pkg/skymailbridge, which is what a host already running Postfix uses.
Package skymail pkg/skymail/render.go c4-app-mail
Package skymail pkg/skymail/send.go c4-app-mail
Package skymail pkg/skymail/units.go c4-app-mail
Index ¶
- Constants
- Variables
- func FormatAge(d time.Duration) string
- func FormatSize(n int64) string
- func ParseAge(s string) (time.Duration, error)
- func ParseSize(s string) (int64, error)
- type Attachment
- type AttachmentData
- type Config
- type Delivered
- type Limits
- type Mailbox
- func (mb *Mailbox) Address(local, suffix string) string
- func (mb *Mailbox) Attachment(folder, id string, n int) (*AttachmentData, error)
- func (mb *Mailbox) Delete(folder, id string) error
- func (mb *Mailbox) Expire(now time.Time) (int, error)
- func (mb *Mailbox) Limits() Limits
- func (mb *Mailbox) List(folder string) ([]Summary, error)
- func (mb *Mailbox) MarkSeen(folder, id string) error
- func (mb *Mailbox) MaxMessageSize() int64
- func (mb *Mailbox) Raw(folder, id string) ([]byte, error)
- func (mb *Mailbox) RunExpiry(ctx context.Context)
- func (mb *Mailbox) Send(ctx context.Context, out Outgoing) (*SendResult, error)
- func (mb *Mailbox) Serve(ctx context.Context, lis net.Listener) error
- func (mb *Mailbox) SetLimits(l Limits)
- func (mb *Mailbox) SetWhitelist(pks []cipher.PubKey) error
- func (mb *Mailbox) Usage() (int64, error)
- func (mb *Mailbox) Whitelist() []cipher.PubKey
- type Outgoing
- type OutgoingAttachment
- type RcptResult
- type Rendered
- type SendResult
- type Summary
Constants ¶
const ( DefaultMaxMessageSize int64 = 1 << 20 // 1 MiB DefaultMaxTotalSize int64 = 16 << 20 // 16 MiB, Inbox and Sent together DefaultMaxAge = 7 * 24 * time.Hour )
Default limits. The mailbox is on by default and open to every PK, so they are low enough that nobody can fill a browser's storage with it: a full mailbox refuses mail until expiry or a delete frees room.
const ( FolderInbox = "INBOX" FolderSent = "Sent" )
Folder names. Inbox is the Maildir root; others are Maildir++ subfolders ("." + name), which is what Dovecot or mutt would open.
const PeerHeader = "X-Skymail-Peer"
PeerHeader carries the sender PK the receiving visor authenticated. The mailbox writes it at the top of every message it accepts, so the first occurrence is always its own; one a sender forged sits below.
Variables ¶
var ErrMailboxFull = errors.New("skymail: mailbox full")
ErrMailboxFull is returned when a message does not fit the quota.
var ErrNotFound = errors.New("skymail: no such message")
ErrNotFound is returned for a message id that is not in the folder.
var Suffixes = []string{".skynet", ".dmsg"}
Suffixes are the address TLDs a mailbox answers to. Both name the same PK; they differ only in which network a sender dials.
Functions ¶
func FormatSize ¶
FormatSize writes a size the way ParseSize reads it.
Types ¶
type Attachment ¶
type Attachment struct {
Name string `json:"name"`
ContentType string `json:"content_type"`
Size int `json:"size"`
}
Attachment names a non-text part of a message.
type AttachmentData ¶
type AttachmentData struct {
Name string `json:"name"`
ContentType string `json:"content_type"`
Data []byte `json:"data"`
}
AttachmentData is one attachment, decoded.
func ExtractAttachment ¶
func ExtractAttachment(raw []byte, n int) (*AttachmentData, error)
ExtractAttachment decodes attachment n, numbered as Render lists them.
type Config ¶
type Config struct {
// Dir is the Maildir root. Inbox lives here, Sent in Dir/.Sent.
Dir string
// PK is the mailbox owner: mail is accepted only for <x>@<PK>.
PK cipher.PubKey
// PeerPK names the authenticated remote PK of an inbound
// connection. The visor supplies it (dmsg and skynet addresses
// differ); ok=false means the caller cannot be identified.
PeerPK func(net.Conn) (cipher.PubKey, bool)
// Dialers reach a peer's port 25, keyed by address suffix. A
// suffix with no dialer cannot be sent to.
Dialers map[string]skymailbridge.Dialer
// Limits bound what the mailbox keeps; zero fields take defaults.
Limits Limits
// OnDeliver, when set, is told of each message the network files in the
// inbox, once it is stored. It must not block.
OnDeliver func(Delivered)
Log logrus.FieldLogger
}
Config is what a Mailbox needs from its host.
type Limits ¶
type Limits struct {
MaxMessageSize int64 `json:"max_message_size"`
MaxTotalSize int64 `json:"max_total_size"`
MaxAge time.Duration `json:"max_age"`
}
Limits bound what a mailbox keeps. A zero field means its default; a negative one removes that bound.
func (Limits) WithDefaults ¶
WithDefaults resolves zero fields to the defaults.
type Mailbox ¶
type Mailbox struct {
// contains filtered or unexported fields
}
Mailbox is one PK's mail: a Maildir, an SMTP receiver policy, and a sender. Safe for concurrent use.
func (*Mailbox) Address ¶
Address returns the mailbox's address for local part and suffix, e.g. "me@<base32-pk>.skynet".
func (*Mailbox) Attachment ¶
func (mb *Mailbox) Attachment(folder, id string, n int) (*AttachmentData, error)
Attachment decodes attachment n of a message.
func (*Mailbox) MaxMessageSize ¶
MaxMessageSize is what the SMTP session advertises and enforces.
func (*Mailbox) Send ¶
Send delivers out to every recipient's visor now, over the network its address names, and files a copy in Sent if any delivery worked. Recipients at this mailbox's own PK are filed directly.
func (*Mailbox) SetLimits ¶
SetLimits replaces the limits; zero fields take their defaults. It applies at once: the next session advertises the new size, and a lowered MaxAge expires what it now excludes on the next sweep.
func (*Mailbox) SetWhitelist ¶
SetWhitelist replaces the set of PKs allowed to deliver and saves it. An empty set accepts mail from any PK, as an unrestricted `serve` port does.
type Outgoing ¶
type Outgoing struct {
// From is a local part ("me") or a full address of this mailbox.
// Empty means "mail".
From string `json:"from,omitempty"`
To []string `json:"to"`
Cc []string `json:"cc,omitempty"`
Subject string `json:"subject"`
Body string `json:"body"`
InReplyTo string `json:"in_reply_to,omitempty"`
// Attachments go after the text as a multipart/mixed message.
Attachments []OutgoingAttachment `json:"attachments,omitempty"`
}
Outgoing is a plain-text message to send.
type OutgoingAttachment ¶
type OutgoingAttachment struct {
Name string `json:"name"`
ContentType string `json:"content_type,omitempty"` // default application/octet-stream
Data []byte `json:"data"`
}
OutgoingAttachment is one file to send.
type RcptResult ¶
type RcptResult struct {
Rcpt string `json:"rcpt"`
Err string `json:"error,omitempty"`
// Via is the network that carried it: "skynet", "dmsg", or "local"
// for this mailbox's own PK.
Via string `json:"via,omitempty"`
}
RcptResult is the outcome for one recipient. Delivery is immediate: a recipient whose visor cannot be reached now gets an error, not a queue entry.
type Rendered ¶
type Rendered struct {
From string `json:"from"`
To string `json:"to"`
Cc string `json:"cc,omitempty"`
Subject string `json:"subject"`
Date string `json:"date"`
MessageID string `json:"message_id,omitempty"`
PeerPK string `json:"peer_pk,omitempty"`
Verified bool `json:"from_verified"`
Text string `json:"text"`
FromHTML bool `json:"from_html,omitempty"` // Text was reduced from an HTML-only part
Attachments []Attachment `json:"attachments,omitempty"`
}
Rendered is a message reduced to what a reader shows.
type SendResult ¶
type SendResult struct {
ID string `json:"id,omitempty"` // the Sent copy, when anything was delivered
MessageID string `json:"message_id"`
Recipients []RcptResult `json:"recipients"`
}
SendResult is what Send reports.
type Summary ¶
type Summary struct {
ID string `json:"id"`
Folder string `json:"folder"`
From string `json:"from"`
To string `json:"to"`
Subject string `json:"subject"`
Date time.Time `json:"date"`
Seen bool `json:"seen"`
Size int64 `json:"size"`
// PeerPK is the sender PK the transport authenticated (inbox only).
PeerPK string `json:"peer_pk,omitempty"`
// FromVerified is true when the From address names PeerPK itself.
FromVerified bool `json:"from_verified"`
}
Summary is one message as a list shows it.