// Command mimecheck is a throwaway feasibility spike for OpenMail's core // architectural bet (see ARCHITECTURE.md §0, §9): can Mox's `message` package // parse a raw RFC 5322 message standalone — outside Mox's store/config/global // state — given only an io.ReaderAt? // // If this builds and runs without dragging in mox-/store/config, "embed Mox as // a library" (Option B) is viable. Run: go run ./spike/mimecheck package main import ( "bytes" "fmt" "log/slog" "os" "strings" "github.com/mjl-/mox/message" ) // A deliberately messy real-world-ish message: multipart/alternative (text+html) // with a reply quote, threading headers, and an attachment part. const sampleEML = "From: Alice \r\n" + "To: agent@openmail.test\r\n" + "Subject: Re: invoice #42\r\n" + "Message-ID: \r\n" + "In-Reply-To: \r\n" + "References: \r\n" + "Date: Mon, 21 Jun 2026 12:00:00 +0000\r\n" + "MIME-Version: 1.0\r\n" + "Content-Type: multipart/mixed; boundary=\"OUTER\"\r\n" + "\r\n" + "--OUTER\r\n" + "Content-Type: multipart/alternative; boundary=\"INNER\"\r\n" + "\r\n" + "--INNER\r\n" + "Content-Type: text/plain; charset=utf-8\r\n" + "\r\n" + "Thanks, looks good to me.\r\n" + "\r\n" + "On Mon, Alice wrote:\r\n" + "> here is the invoice\r\n" + "--INNER\r\n" + "Content-Type: text/html; charset=utf-8\r\n" + "\r\n" + "

Thanks, looks good to me.

\r\n" + "--INNER--\r\n" + "--OUTER\r\n" + "Content-Type: application/pdf; name=\"invoice.pdf\"\r\n" + "Content-Disposition: attachment; filename=\"invoice.pdf\"\r\n" + "Content-Transfer-Encoding: base64\r\n" + "\r\n" + "JVBERi0xLjQK\r\n" + "--OUTER--\r\n" func main() { log := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelWarn})) r := bytes.NewReader([]byte(sampleEML)) // EnsurePart fully parses header + walks the MIME tree given the size. p, err := message.EnsurePart(log, false, r, int64(len(sampleEML))) if err != nil { fmt.Fprintf(os.Stderr, "FAIL: parse error: %v\n", err) os.Exit(1) } fmt.Println("=== mox/message standalone parse OK ===") if p.Envelope != nil { e := p.Envelope fmt.Printf("Subject: %s\n", e.Subject) fmt.Printf("MessageID: %s\n", e.MessageID) fmt.Printf("InReplyTo: %s\n", e.InReplyTo) if len(e.From) > 0 { fmt.Printf("From: %s@%s\n", e.From[0].User, e.From[0].Host) } } fmt.Printf("Top type: %s/%s\n", p.MediaType, p.MediaSubType) // Walk the tree, summarizing each leaf — proves multipart traversal works. var textBody string var attachments int var walk func(parts []message.Part, depth int) walk = func(parts []message.Part, depth int) { for i := range parts { sp := &parts[i] indent := strings.Repeat(" ", depth) disp := "" if sp.ContentDisposition != nil { disp = " [" + *sp.ContentDisposition + "]" } fmt.Printf("%s- %s/%s%s\n", indent, sp.MediaType, sp.MediaSubType, disp) if sp.ContentDisposition != nil && strings.EqualFold(*sp.ContentDisposition, "attachment") { attachments++ } if sp.MediaType == "TEXT" && sp.MediaSubType == "PLAIN" && textBody == "" { if buf, rerr := readPart(sp); rerr == nil { textBody = string(buf) } } walk(sp.Parts, depth+1) } } fmt.Println("Structure:") walk(p.Parts, 1) fmt.Printf("\nAttachments found: %d\n", attachments) fmt.Printf("text/plain body:\n%s\n", indentBlock(textBody)) fmt.Println("=== SPIKE PASSED: Mox message parsing is usable standalone ===") } func readPart(p *message.Part) ([]byte, error) { rd := p.Reader() var b bytes.Buffer _, err := b.ReadFrom(rd) return b.Bytes(), err } func indentBlock(s string) string { out := []string{} for _, line := range strings.Split(strings.TrimRight(s, "\r\n"), "\n") { out = append(out, " | "+strings.TrimRight(line, "\r")) } return strings.Join(out, "\n") }