emlbuilder

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Apr 1, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package emlbuilder provides a Lark-API-compatible RFC 2822 EML message builder.

It is designed for use with the Lark mail drafts API (POST /open-apis/mail/v1/user_mailboxes/me/drafts), which requires the complete EML to be base64url-encoded and placed in the "raw" request field. After creating a draft, send it via POST .../drafts/{draft_id}/send.

Key differences from standard MIME libraries:

  • Line endings are LF (\n), not CRLF — Lark API requires this.
  • Content-Type parameters are never folded onto a new line — Lark's MIME parser does not handle header folding correctly.
  • Non-ASCII body content is encoded as base64 (StdEncoding) — 7bit and 8bit are rejected by Lark for non-ASCII content.
  • BuildBase64URL() produces the base64url (URLEncoding) output that goes directly into the API's "raw" field.

MIME structure produced by Build():

multipart/mixed              ← only when attachments exist
└─ multipart/related         ← only when CID inline/other parts exist
   └─ multipart/alternative  ← only when multiple body types coexist
      ├─ text/plain
      ├─ text/html
      └─ text/calendar
   └─ inline/other parts (CID)
└─ attachments

Usage:

raw, err := emlbuilder.New().
    From("", "alice@example.com").
    To("", "bob@example.com").
    Subject("Hello").
    TextBody([]byte("Hi Bob")).
    HTMLBody([]byte("<p>Hi Bob</p>")).
    AddInline(imgBytes, "image/png", "logo.png", "logo").
    BuildBase64URL()

Index

Constants

View Source
const MaxEMLSize = 25 * 1024 * 1024 // 25 MB

MaxEMLSize is the maximum allowed raw EML size in bytes.

Variables

This section is empty.

Functions

This section is empty.

Types

type Builder

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

Builder constructs a Lark-compatible RFC 2822 EML message. All setter methods return a copy of the Builder (immutable/fluent style), so a base builder can be reused across multiple goroutines safely.

func New

func New() Builder

New returns an empty Builder.

func (Builder) AddAttachment

func (b Builder) AddAttachment(content []byte, contentType, fileName string) Builder

AddAttachment appends a file attachment. contentType should be a valid MIME type (e.g. "application/pdf"). If contentType is empty, "application/octet-stream" is used. Returns an error builder if contentType or fileName contains CR or LF.

func (Builder) AddFileAttachment

func (b Builder) AddFileAttachment(path string) Builder

AddFileAttachment reads a file from disk and appends it as an attachment. The backend canonicalizes regular attachments to application/octet-stream on save/readback, so the builder aligns with that behavior instead of inferring a richer MIME type from the local file extension. If reading the file fails, the error is stored and returned by Build().

func (Builder) AddFileInline

func (b Builder) AddFileInline(path, contentID string) Builder

AddFileInline reads a file from disk and appends it as a CID inline part. The content type is inferred from the file extension. If reading the file fails, the error is stored and returned by Build().

func (Builder) AddFileOtherPart

func (b Builder) AddFileOtherPart(path, contentID string) Builder

AddFileOtherPart reads a file from disk and appends it as a CID other-part (no Content-Disposition header). See AddOtherPart for details. If reading the file fails, the error is stored and returned by Build().

func (Builder) AddInline

func (b Builder) AddInline(content []byte, contentType, fileName, contentID string) Builder

AddInline appends a CID-referenced inline part (e.g. an embedded image). The part is written with Content-Disposition: inline, causing most mail clients to render it inline rather than as a download. contentID is a unique identifier without angle brackets; it matches the "cid:" reference in the HTML body (e.g. contentID="logo.png" matches src="cid:logo.png"). When inline parts are present, the message body is automatically wrapped in multipart/related. Returns an error builder if contentType or fileName contains CR or LF, or if contentID contains any ASCII control character.

func (Builder) AddOtherPart

func (b Builder) AddOtherPart(content []byte, contentType, fileName, contentID string) Builder

AddOtherPart appends a CID-referenced embedded part without Content-Disposition. Unlike AddInline, this part carries no Content-Disposition header, which is appropriate for resources referenced via "cid:" that should not appear as inline attachments in the client UI (e.g. calendar objects or custom data blobs). When other parts are present, the message body is automatically wrapped in multipart/related. Returns an error builder if contentType or fileName contains CR or LF, or if contentID contains any ASCII control character.

func (Builder) AllRecipients

func (b Builder) AllRecipients() []string

AllRecipients returns all recipient addresses (To + CC + BCC). Useful for SMTP envelope construction.

func (Builder) AllowNoRecipients

func (b Builder) AllowNoRecipients() Builder

AllowNoRecipients tells Build() to skip the recipient-required check. Use this for draft creation, where saving without recipients is valid.

func (Builder) BCC

func (b Builder) BCC(name, addr string) Builder

BCC appends an address to the Bcc list. Bcc addresses are included in AllRecipients() but not written to the EML headers.

func (Builder) BCCAddrs

func (b Builder) BCCAddrs(addrs []mail.Address) Builder

BCCAddrs sets the Bcc list to the given address list.

func (Builder) Build

func (b Builder) Build() ([]byte, error)

Build validates the builder and returns the raw EML bytes.

Constraints (Lark API requirements):

  • From is mandatory.
  • At least one of To/CC/BCC must be set.
  • Line endings are LF (\n), not CRLF.
  • Content-Type parameters are written on a single line (no header folding).
  • Non-ASCII body content is base64 (StdEncoding) encoded.

func (Builder) BuildBase64URL

func (b Builder) BuildBase64URL() (string, error)

BuildBase64URL returns the EML encoded as base64url (RFC 4648). This is the value to place in the Lark API "raw" field.

func (Builder) CC

func (b Builder) CC(name, addr string) Builder

CC appends an address to the Cc header. name may be empty.

func (Builder) CCAddrs

func (b Builder) CCAddrs(addrs []mail.Address) Builder

CCAddrs sets the Cc header to the given address list.

func (Builder) CalendarBody

func (b Builder) CalendarBody(body []byte) Builder

CalendarBody sets the text/calendar body (e.g. for meeting invitations). May be combined with TextBody and/or HTMLBody; the resulting parts are wrapped in multipart/alternative.

func (Builder) Date

func (b Builder) Date(date time.Time) Builder

Date sets the Date header. If not set, Build() uses time.Now().

func (Builder) Error

func (b Builder) Error() error

Error returns any stored error (e.g. from AddFileAttachment), or nil.

func (Builder) From

func (b Builder) From(name, addr string) Builder

From sets the From header. name may be empty.

func (Builder) HTMLBody

func (b Builder) HTMLBody(body []byte) Builder

HTMLBody sets the text/html body.

func (Builder) Header

func (b Builder) Header(name, value string) Builder

Header appends an extra header to the message. Multiple calls with the same name result in multiple header lines. Returns an error builder if name or value contains CR, LF, or (for names) ':'.

func (Builder) InReplyTo

func (b Builder) InReplyTo(id string) Builder

InReplyTo sets the In-Reply-To header (the smtp_message_id of the original mail, without angle brackets). Used for reply threading. Returns an error builder if id contains CR or LF.

func (Builder) LMSReplyToMessageID

func (b Builder) LMSReplyToMessageID(id string) Builder

LMSReplyToMessageID sets the Lark internal message_id of the original message. Written as X-LMS-Reply-To-Message-Id when In-Reply-To is also set. Returns an error builder if id contains CR or LF.

func (Builder) MessageID

func (b Builder) MessageID(id string) Builder

MessageID sets the Message-ID header value (without angle brackets). If not set, Build() generates a unique ID. Returns an error builder if id contains CR or LF.

func (Builder) References

func (b Builder) References(refs string) Builder

References sets the References header value verbatim. Typically a space-separated list of message IDs including angle brackets, e.g. "<id1@host> <id2@host>". Returns an error builder if refs contains CR or LF.

func (Builder) ReplyTo

func (b Builder) ReplyTo(name, addr string) Builder

ReplyTo appends an address to the Reply-To header. name may be empty.

func (Builder) Subject

func (b Builder) Subject(subject string) Builder

Subject sets the Subject header. Non-ASCII characters are automatically RFC 2047 B-encoded. Returns an error builder if subject contains CR or LF.

func (Builder) TextBody

func (b Builder) TextBody(body []byte) Builder

TextBody sets the text/plain body.

func (Builder) To

func (b Builder) To(name, addr string) Builder

To appends an address to the To header. name may be empty.

func (Builder) ToAddrs

func (b Builder) ToAddrs(addrs []mail.Address) Builder

ToAddrs sets the To header to the given address list.

Jump to

Keyboard shortcuts

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