Repository navigation
Tags: mattt/Envelope
Tags
Read messages that Mail stores only as partial files (#7) Mail writes <rowid>.partial.emlx when it stores some parts of a message, such as attachments and inline images, in separate files. The partial file keeps the headers and the text parts, and leaves the body of each separate part empty, with an X-Apple-Content-Length field. Envelope threw MailError.partialMessage for these messages. The reader now reads the partial file when no complete .emlx file exists, with the same containment and size checks. Content.attachments lists the parts that have a filename or that Mail stores separately, and isStoredSeparately marks the parts whose content the file leaves out. A part that Mail stores separately cannot supply the body; when no other part can, Content throws EmlxError.partialMessage. MailError.partialMessage is deprecated, and its text no longer says that opening the message in Mail downloads it.
Read account addresses that Mail records as the account URL authority (… …#5) Current stores record an IMAP account's address as the whole authority of its AccountURL, such as imap://user%40example.com/, so URLComponents reports the address as the host and no user. Read the address from the host when the URL has no user, and keep reading the user form. Log why the account map gives no address: a missing, unreadable, or unrecognized map, an entry without an address, or an account that mailboxes refer to but the map does not list.
Merge everything into one Envelope module, and adopt iMCP's API sugge… …stions (#4) * Merge Mail, Emlx, and MIME into one Envelope module Clients qualify Envelope's types with a distinctive module name, such as Envelope.MailError, and the package no longer adds generic module names like Mail and MIME to a dependency graph. The sources keep their Mail, Emlx, and MIME folders. * Find the store location without waiting for other calls location() reads only directory entries and links, so a status check no longer waits behind a running search or read. * Validate Configuration when it is created, so Store.init does not throw Configuration.init throws for a limit that is not positive, and Configuration.default holds the default limits. Callers no longer handle an error that the default configuration cannot produce. * Add Mailbox.ID with a string form that includes the store Mailbox row identifiers belong to one store, so a stale identifier now fails with storeChanged instead of naming a different mailbox. Mailbox.ID, Message.Identifier, and FetchRequest.Cursor encode as their string forms, so clients that send them as JSON strings no longer parse them by hand. * Document a long-lived store with a security-scoped bookmark Sandboxed clients keep one store created from the URL resolved from the bookmark, and make the folder accessible for each call. The README also points to 0.3.0.
Replace Worker and Database with a Mail.Store actor (#3) * Replace Worker and Database with a Mail.Store actor Store runs each operation on a private dispatch queue as part of the calling task, so task cancellation reaches SQLite and parsing without a token. Overlapping calls wait instead of failing with operationInProgress, and each operation closes its connection before it reads message files. Store.init validates the configuration, which adds a snapshot time limit. checkAccess() checks that the index can be opened. Operations run at the calling task's priority on macOS 14 and later. Cursors replace offsets for pagination. The new Envelope product re-exports Mail and Emlx and adds Store.content(for:), which checks the message's identity. * Rewrite the README for Mail.Store The usage examples use the Envelope product, cursor pagination, and task cancellation.
Add scoped reads that close the connection before returning (#2) * Add scoped reads that close the connection before returning Database.read runs a closure in one read transaction and closes the connection when it returns or throws. MessageFileReader.read(_:root:) finds the store from the Mail folder, so callers no longer carry versionURL from a closed database. * Use scoped reads in the README examples The read example no longer closes the database twice.