webmail

package
v0.0.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2024 License: MIT Imports: 58 Imported by: 1

Documentation

Overview

Package webmail implements a webmail client, serving html/js and providing an API for message actions and SSE endpoint for receiving real-time updates.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Handler

func Handler(maxMessageSize int64, cookiePath string, isForwarded bool, accountPath string) func(w http.ResponseWriter, r *http.Request)

Handler returns a handler for the webmail endpoints, customized for the max message size coming from the listener and cookiePath.

Types

type Attachment

type Attachment struct {
	Path []int // Indices into top-level message.Part.Parts.

	// File name based on "name" attribute of "Content-Type", or the "filename"
	// attribute of "Content-Disposition".
	Filename string

	Part message.Part
}

Attachment is a MIME part is an existing message that is not intended as viewable text or HTML part.

type AttachmentType

type AttachmentType string

AttachmentType is for filtering by attachment type.

const (
	AttachmentIndifferent  AttachmentType = ""
	AttachmentNone         AttachmentType = "none"
	AttachmentAny          AttachmentType = "any"
	AttachmentImage        AttachmentType = "image" // png, jpg, gif, ...
	AttachmentPDF          AttachmentType = "pdf"
	AttachmentArchive      AttachmentType = "archive"      // zip files, tgz, ...
	AttachmentSpreadsheet  AttachmentType = "spreadsheet"  // ods, xlsx, ...
	AttachmentDocument     AttachmentType = "document"     // odt, docx, ...
	AttachmentPresentation AttachmentType = "presentation" // odp, pptx, ...
)

type ChangeMailboxAdd

type ChangeMailboxAdd struct {
	Mailbox store.Mailbox
}

ChangeMailboxAdd indicates a new mailbox was added, initially without any messages.

type ChangeMailboxCounts

type ChangeMailboxCounts struct {
	store.ChangeMailboxCounts
}

ChangeMailboxCounts set new total and unseen message counts for a mailbox.

type ChangeMailboxKeywords

type ChangeMailboxKeywords struct {
	store.ChangeMailboxKeywords
}

ChangeMailboxKeywords has an updated list of keywords for a mailbox, e.g. after a message was added with a keyword that wasn't in the mailbox yet.

type ChangeMailboxRemove

type ChangeMailboxRemove struct {
	store.ChangeRemoveMailbox
}

ChangeMailboxRemove indicates a mailbox was removed, including all its messages.

type ChangeMailboxRename

type ChangeMailboxRename struct {
	store.ChangeRenameMailbox
}

ChangeMailboxRename indicates a mailbox was renamed. Its ID stays the same. It could be under a new parent.

type ChangeMailboxSpecialUse

type ChangeMailboxSpecialUse struct {
	store.ChangeMailboxSpecialUse
}

ChangeMailboxSpecialUse has updated special-use flags for a mailbox.

type ChangeMsgAdd

type ChangeMsgAdd struct {
	store.ChangeAddUID
	MessageItems []MessageItem
}

ChangeMsgAdd adds a new message and possibly its thread to the view.

type ChangeMsgFlags

type ChangeMsgFlags struct {
	store.ChangeFlags
}

ChangeMsgFlags updates flags for one message.

type ChangeMsgRemove

type ChangeMsgRemove struct {
	store.ChangeRemoveUIDs
}

ChangeMsgRemove removes one or more messages from the view.

type ChangeMsgThread added in v0.0.7

type ChangeMsgThread struct {
	store.ChangeThread
}

ChangeMsgThread updates muted/collapsed fields for one message.

type ComposeMessage added in v0.0.11

type ComposeMessage struct {
	From              string
	To                []string
	Cc                []string
	Bcc               []string
	ReplyTo           string // If non-empty, Reply-To header to add to message.
	Subject           string
	TextBody          string
	ResponseMessageID int64 // If set, this was a reply or forward, based on IsForward.
	DraftMessageID    int64 // If set, previous draft message that will be removed after composing new message.
}

ComposeMessage is a message to be composed, for saving draft messages.

type DomainAddressConfig

type DomainAddressConfig struct {
	LocalpartCatchallSeparator string // Can be empty.
	LocalpartCaseSensitive     bool
}

DomainAddressConfig has the address (localpart) configuration for a domain, so the webmail client can decide if an address matches the addresses of the account.

type EventStart

type EventStart struct {
	SSEID                int64
	LoginAddress         MessageAddress
	Addresses            []MessageAddress
	DomainAddressConfigs map[string]DomainAddressConfig // ASCII domain to address config.
	MailboxName          string
	Mailboxes            []store.Mailbox
	RejectsMailbox       string
	Settings             store.Settings
	AccountPath          string // If nonempty, the path on same host to webaccount interface.
	Version              string
}

EventStart is the first message sent on an SSE connection, giving the client basic data to populate its UI. After this event, messages will follow quickly in an EventViewMsgs event.

type EventViewChanges

type EventViewChanges struct {
	ViewID  int64
	Changes [][2]any // The first field of [2]any is a string, the second of the Change types below.
}

EventViewChanges contain one or more changes relevant for the client, either with new mailbox total/unseen message counts, or messages added/removed/modified (flags) for the current view.

type EventViewErr

type EventViewErr struct {
	ViewID    int64
	RequestID int64
	Err       string // To be displayed in client.
	// contains filtered or unexported fields
}

EventViewErr indicates an error during a query for messages. The request is aborted, no more request-related messages will be sent until the next request.

type EventViewMsgs

type EventViewMsgs struct {
	ViewID    int64
	RequestID int64

	// If empty, this was the last message for the request. If non-empty, a list of
	// thread messages. Each with the first message being the reason this thread is
	// included and can be used as AnchorID in followup requests. If the threading mode
	// is "off" in the query, there will always be only a single message. If a thread
	// is sent, all messages in the thread are sent, including those that don't match
	// the query (e.g. from another mailbox). Threads can be displayed based on the
	// ThreadParentIDs field, with possibly slightly different display based on field
	// ThreadMissingLink.
	MessageItems [][]MessageItem

	// If set, will match the target page.DestMessageID from the request.
	ParsedMessage *ParsedMessage

	// If set, there are no more messages in this view at this moment. Messages can be
	// added, typically via Change messages, e.g. for new deliveries.
	ViewEnd bool
}

EventViewMsgs contains messages for a view, possibly a continuation of an earlier list of messages.

type EventViewReset

type EventViewReset struct {
	ViewID    int64
	RequestID int64
}

EventViewReset indicates that a request for the next set of messages in a few could not be fulfilled, e.g. because the anchor message does not exist anymore. The client should clear its list of messages. This can happen before EventViewMsgs events are sent.

type File

type File struct {
	Filename string
	DataURI  string // Full data of the attachment, with base64 encoding and including content-type.
}

File is a new attachment (not from an existing message that is being forwarded) to send with a SubmitMessage.

type Filter

type Filter struct {
	// If -1, then all mailboxes except Trash/Junk/Rejects. Otherwise, only active if > 0.
	MailboxID int64

	// If true, also submailboxes are included in the search.
	MailboxChildrenIncluded bool

	// In case client doesn't know mailboxes and their IDs yet. Only used during sse
	// connection setup, where it is turned into a MailboxID. Filtering only looks at
	// MailboxID.
	MailboxName string

	Words       []string // Case insensitive substring match for each string.
	From        []string
	To          []string // Including Cc and Bcc.
	Oldest      *time.Time
	Newest      *time.Time
	Subject     []string
	Attachments AttachmentType
	Labels      []string
	Headers     [][2]string // Header values can be empty, it's a check if the header is present, regardless of value.
	SizeMin     int64
	SizeMax     int64
}

Filter selects the messages to return. Fields that are set must all match, for slices each element by match ("and").

type ForwardAttachments

type ForwardAttachments struct {
	MessageID int64   // Only relevant if MessageID is not 0.
	Paths     [][]int // List of attachments, each path is a list of indices into the top-level message.Part.Parts.
}

ForwardAttachments references attachments by a list of message.Part paths.

type MessageAddress

type MessageAddress struct {
	Name   string // Free-form name for display in mail applications.
	User   string // Localpart, encoded.
	Domain dns.Domain
}

MessageAddress is like message.Address, but with a dns.Domain, with unicode name included.

type MessageEnvelope

type MessageEnvelope struct {
	// todo: should get sherpadoc to understand type embeds and embed the non-MessageAddress fields from message.Envelope.
	Date      time.Time
	Subject   string
	From      []MessageAddress
	Sender    []MessageAddress
	ReplyTo   []MessageAddress
	To        []MessageAddress
	CC        []MessageAddress
	BCC       []MessageAddress
	InReplyTo string
	MessageID string
}

MessageEnvelope is like message.Envelope, as used in message.Part, but including unicode host names for IDNA names.

type MessageItem

type MessageItem struct {
	Message     store.Message // Without ParsedBuf and MsgPrefix, for size.
	Envelope    MessageEnvelope
	Attachments []Attachment
	IsSigned    bool
	IsEncrypted bool
	FirstLine   string // Of message body, for showing as preview.
	MatchQuery  bool   // If message does not match query, it can still be included because of threading.
}

MessageItem is sent by queries, it has derived information analyzed from message.Part, made for the needs of the message items in the message list. messages.

type NotFilter

type NotFilter struct {
	Words       []string
	From        []string
	To          []string
	Subject     []string
	Attachments AttachmentType
	Labels      []string
}

NotFilter matches messages that don't match these fields.

type Page

type Page struct {
	// Start returning messages after this ID, if > 0. For pagination, fetching the
	// next set of messages.
	AnchorMessageID int64

	// Number of messages to return, must be >= 1, we never return more than 10000 for
	// one request.
	Count int

	// If > 0, return messages until DestMessageID is found. More than Count messages
	// can be returned. For long-running searches, it may take a while before this
	// message if found.
	DestMessageID int64
}

Page holds pagination parameters for a request.

type ParsedMessage

type ParsedMessage struct {
	ID       int64
	Part     message.Part
	Headers  map[string][]string
	ViewMode store.ViewMode

	// Text parts, can be empty.
	Texts []string

	// Whether there is an HTML part. The webclient renders HTML message parts through
	// an iframe and a separate request with strict CSP headers to prevent script
	// execution and loading of external resources, which isn't possible when loading
	// in iframe with inline HTML because not all browsers support the iframe csp
	// attribute.
	HasHTML bool

	ListReplyAddress *MessageAddress // From List-Post.
	// contains filtered or unexported fields
}

ParsedMessage has more parsed/derived information about a message, intended for rendering the (contents of the) message. Information from MessageItem is not duplicated.

type Query

type Query struct {
	OrderAsc  bool // Order by received ascending or desending.
	Threading ThreadMode
	Filter    Filter
	NotFilter NotFilter
}

Query is a request for messages that match filters, in a given order.

type RecipientSecurity added in v0.0.8

type RecipientSecurity struct {
	// Whether recipient domain supports (opportunistic) STARTTLS, as seen during most
	// recent delivery attempt. Will be "unknown" if no delivery to the domain has been
	// attempted yet.
	STARTTLS SecurityResult

	// Whether we have a stored enforced MTA-STS policy, or domain has MTA-STS DNS
	// record.
	MTASTS SecurityResult

	// Whether MX lookup response was DNSSEC-signed.
	DNSSEC SecurityResult

	// Whether first delivery destination has DANE records.
	DANE SecurityResult

	// Whether recipient domain is known to implement the REQUIRETLS SMTP extension.
	// Will be "unknown" if no delivery to the domain has been attempted yet.
	RequireTLS SecurityResult
}

RecipientSecurity is a quick analysis of the security properties of delivery to the recipient (domain).

type Request

type Request struct {
	ID int64

	SSEID int64 // SSE connection.

	// To indicate a request is a continuation (more results) of the previous view.
	// Echoed in events, client checks if it is getting results for the latest request.
	ViewID int64

	// If set, this request and its view are canceled. A new view must be started.
	Cancel bool

	Query Query
	Page  Page
}

Request is a request to an SSE connection to send messages, either for a new view, to continue with an existing view, or to a cancel an ongoing request.

type SecurityResult added in v0.0.8

type SecurityResult string

SecurityResult indicates whether a security feature is supported.

const (
	SecurityResultError SecurityResult = "error"
	SecurityResultNo    SecurityResult = "no"
	SecurityResultYes   SecurityResult = "yes"
	// Unknown whether supported. Finding out may only be (reasonably) possible when
	// trying (e.g. SMTP STARTTLS). Once tried, the result may be cached for future
	// lookups.
	SecurityResultUnknown SecurityResult = "unknown"
)

type SubmitMessage

type SubmitMessage struct {
	From               string
	To                 []string
	Cc                 []string
	Bcc                []string
	ReplyTo            string // If non-empty, Reply-To header to add to message.
	Subject            string
	TextBody           string
	Attachments        []File
	ForwardAttachments ForwardAttachments
	IsForward          bool
	ResponseMessageID  int64      // If set, this was a reply or forward, based on IsForward.
	UserAgent          string     // User-Agent header added if not empty.
	RequireTLS         *bool      // For "Require TLS" extension during delivery.
	FutureRelease      *time.Time // If set, time (in the future) when message should be delivered from queue.
	ArchiveThread      bool       // If set, thread is archived after sending message.
	DraftMessageID     int64      // If set, draft message that will be removed after sending.
}

SubmitMessage is an email message to be sent to one or more recipients. Addresses are formatted as just email address, or with a name like "name <user@host>".

type ThreadMode added in v0.0.7

type ThreadMode string
const (
	ThreadOff    ThreadMode = "off"
	ThreadOn     ThreadMode = "on"
	ThreadUnread ThreadMode = "unread"
)

type Webmail

type Webmail struct {
	// contains filtered or unexported fields
}

func (Webmail) CompleteRecipient

func (Webmail) CompleteRecipient(ctx context.Context, search string) ([]string, bool)

CompleteRecipient returns autocomplete matches for a recipient, returning the matches, most recently used first, and whether this is the full list and further requests for longer prefixes aren't necessary.

func (Webmail) DecodeMIMEWords added in v0.0.10

func (Webmail) DecodeMIMEWords(ctx context.Context, text string) string

DecodeMIMEWords decodes Q/B-encoded words for a mime headers into UTF-8 text.

func (Webmail) FlagsAdd

func (Webmail) FlagsAdd(ctx context.Context, messageIDs []int64, flaglist []string)

FlagsAdd adds flags, either system flags like \Seen or custom keywords. The flags should be lower-case, but will be converted and verified.

func (Webmail) FlagsClear

func (Webmail) FlagsClear(ctx context.Context, messageIDs []int64, flaglist []string)

FlagsClear clears flags, either system flags like \Seen or custom keywords.

func (Webmail) FromAddressSettingsSave added in v0.0.11

func (Webmail) FromAddressSettingsSave(ctx context.Context, fas store.FromAddressSettings)

FromAddressSettingsSave saves per-"From"-address settings.

func (Webmail) Login added in v0.0.9

func (w Webmail) Login(ctx context.Context, loginToken, username, password string) store.CSRFToken

Login returns a session token for the credentials, or fails with error code "user:badLogin". Call LoginPrep to get a loginToken.

func (Webmail) LoginPrep added in v0.0.9

func (w Webmail) LoginPrep(ctx context.Context) string

LoginPrep returns a login token, and also sets it as cookie. Both must be present in the call to Login.

func (Webmail) Logout added in v0.0.9

func (w Webmail) Logout(ctx context.Context)

Logout invalidates the session token.

func (Webmail) MailboxCreate

func (Webmail) MailboxCreate(ctx context.Context, name string)

MailboxCreate creates a new mailbox.

func (Webmail) MailboxDelete

func (Webmail) MailboxDelete(ctx context.Context, mailboxID int64)

MailboxDelete deletes a mailbox and all its messages.

func (Webmail) MailboxEmpty

func (Webmail) MailboxEmpty(ctx context.Context, mailboxID int64)

MailboxEmpty empties a mailbox, removing all messages from the mailbox, but not its child mailboxes.

func (Webmail) MailboxRename

func (Webmail) MailboxRename(ctx context.Context, mailboxID int64, newName string)

MailboxRename renames a mailbox, possibly moving it to a new parent. The mailbox ID and its messages are unchanged.

func (Webmail) MailboxSetSpecialUse

func (Webmail) MailboxSetSpecialUse(ctx context.Context, mb store.Mailbox)

MailboxSetSpecialUse sets the special use flags of a mailbox.

func (Webmail) MessageCompose added in v0.0.11

func (w Webmail) MessageCompose(ctx context.Context, m ComposeMessage, mailboxID int64) (id int64)

MessageCompose composes a message and saves it to the mailbox. Used for saving draft messages.

func (Webmail) MessageDelete

func (Webmail) MessageDelete(ctx context.Context, messageIDs []int64)

MessageDelete permanently deletes messages, without moving them to the Trash mailbox.

func (Webmail) MessageFindMessageID added in v0.0.11

func (Webmail) MessageFindMessageID(ctx context.Context, messageID string) (id int64)

MessageFindMessageID looks up a message by Message-Id header, and returns the ID of the message in storage. Used when opening a previously saved draft message for editing again. If no message is find, zero is returned, not an error.

func (Webmail) MessageMove

func (Webmail) MessageMove(ctx context.Context, messageIDs []int64, mailboxID int64)

MessageMove moves messages to another mailbox. If the message is already in the mailbox an error is returned.

func (Webmail) MessageSubmit

func (w Webmail) MessageSubmit(ctx context.Context, m SubmitMessage)

MessageSubmit sends a message by submitting it the outgoing email queue. The message is sent to all addresses listed in the To, Cc and Bcc addresses, without Bcc message header.

If a Sent mailbox is configured, messages are added to it after submitting to the delivery queue. If Bcc addresses were present, a header is prepended to the message stored in the Sent mailbox.

func (Webmail) ParsedMessage

func (Webmail) ParsedMessage(ctx context.Context, msgID int64) (pm ParsedMessage)

ParsedMessage returns enough to render the textual body of a message. It is assumed the client already has other fields through MessageItem.

func (Webmail) RecipientSecurity added in v0.0.8

func (Webmail) RecipientSecurity(ctx context.Context, messageAddressee string) (RecipientSecurity, error)

RecipientSecurity looks up security properties of the address in the single-address message addressee (as it appears in a To/Cc/Bcc/etc header).

func (Webmail) Request

func (Webmail) Request(ctx context.Context, req Request)

Requests sends a new request for an open SSE connection. Any currently active request for the connection will be canceled, but this is done asynchrously, so the SSE connection may still send results for the previous request. Callers should take care to ignore such results. If req.Cancel is set, no new request is started.

func (Webmail) RulesetAdd added in v0.0.11

func (Webmail) RulesetAdd(ctx context.Context, rcptTo string, ruleset config.Ruleset)

func (Webmail) RulesetMailboxNever added in v0.0.11

func (Webmail) RulesetMailboxNever(ctx context.Context, mailboxID int64, toMailbox bool)

func (Webmail) RulesetMessageNever added in v0.0.11

func (Webmail) RulesetMessageNever(ctx context.Context, rcptTo, listID, msgFrom string, toInbox bool)

func (Webmail) RulesetRemove added in v0.0.11

func (Webmail) RulesetRemove(ctx context.Context, rcptTo string, ruleset config.Ruleset)

func (Webmail) RulesetSuggestMove added in v0.0.11

func (Webmail) RulesetSuggestMove(ctx context.Context, msgID, mbSrcID, mbDstID int64) (listID string, msgFrom string, isRemove bool, rcptTo string, ruleset *config.Ruleset)

func (Webmail) SSETypes

func (Webmail) SSETypes() (start EventStart, viewErr EventViewErr, viewReset EventViewReset, viewMsgs EventViewMsgs, viewChanges EventViewChanges, msgAdd ChangeMsgAdd, msgRemove ChangeMsgRemove, msgFlags ChangeMsgFlags, msgThread ChangeMsgThread, mailboxRemove ChangeMailboxRemove, mailboxAdd ChangeMailboxAdd, mailboxRename ChangeMailboxRename, mailboxCounts ChangeMailboxCounts, mailboxSpecialUse ChangeMailboxSpecialUse, mailboxKeywords ChangeMailboxKeywords, flags store.Flags)

SSETypes exists to ensure the generated API contains the types, for use in SSE events.

func (Webmail) SettingsSave added in v0.0.11

func (Webmail) SettingsSave(ctx context.Context, settings store.Settings)

SettingsSave saves settings, e.g. for composing.

func (Webmail) ThreadCollapse added in v0.0.7

func (Webmail) ThreadCollapse(ctx context.Context, messageIDs []int64, collapse bool)

ThreadCollapse saves the ThreadCollapse field for the messages and its children. The messageIDs are typically thread roots. But not all roots (without parent) of a thread need to have the same collapsed state.

func (Webmail) ThreadMute added in v0.0.7

func (Webmail) ThreadMute(ctx context.Context, messageIDs []int64, mute bool)

ThreadMute saves the ThreadMute field for the messages and their children. If messages are muted, they are also marked collapsed.

func (Webmail) Token

func (Webmail) Token(ctx context.Context) string

Token returns a token to use for an SSE connection. A token can only be used for a single SSE connection. Tokens are stored in memory for a maximum of 1 minute, with at most 10 unused tokens (the most recently created) per account.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL