Back to blog
2026-07-06 Thijs Creemers

Release: v1.0.1-alpha-38

This release fixes a silent data-loss bug in the boundary-external SMTP transport: outbound emails could be marked sent while their attachments — and their deduplication Message-ID — never reached the wire (BOU-150).

Fixed: SMTP silently dropped attachments and Message-ID

The boundary-external SMTP MIME builder only handled :body and :html-body. :attachments and :message-id on an outbound email were silently discarded. A send leg could therefore mark a row :sent without ever delivering the PDF, and a deterministic, caller-supplied Message-ID (used for at-most-once dedup) was never emitted — every send generated a fresh one.

The fix, in boundary-external:

  • build-mime-message: when :attachments are present, build a multipart/mixed message — the body (plain, or a nested text/html alternative) as the first part, then one MimeBodyPart per attachment (filename + content type). Attachment :content accepts raw bytes or a base64-encoded string. The no-attachment paths are unchanged.

  • make-mime-message: a MimeMessage whose updateMessageID writes the caller-supplied :message-id (angle-bracket wrapped) so it survives saveChanges and Transport.send instead of being regenerated.

In boundary-email, email→outbound stops dropping :attachments and passes them through to the transport.

Changed: OutboundEmail schema

OutboundEmail gains two optional keys, and a new Attachment schema:

(def Attachment
  [:map
   [:filename     [:string {:min 1}]]
   [:content-type [:string {:min 1}]]
   [:content      [:or :bytes [:string {:min 1}]]]  ; raw bytes or base64
   [:size {:optional true} [:int {:min 0}]]])

;; OutboundEmail now also accepts:
;;   [:attachments {:optional true} [:vector Attachment]]
;;   [:message-id  {:optional true} [:string {:min 1}]]   ; else javax.mail generates one

Both keys are optional, so existing callers are unaffected.

Version alignment

All libraries bumped to v1.0.1-alpha-38 to maintain lockstep versioning.

Upgrade

Re-run the installer to pick up the latest release:

curl -fsSL https://get.boundary-app.org | bash

No migration required. Backward compatible — :attachments and :message-id are opt-in.