NotesMIMEEntity + NotesMIMEHeader: Parsing Email MIME Structure in LotusScript
Your agent needs to parse incoming mail — extract the HTML body, list attachments, or read a specific header like Reply-To or X-Mailer. You open the NotesDocument, call GetItemValue("Body"), and get empty or mangled text.
The problem: modern email is a nested MIME tree — HTML body, plain-text fallback, attachments, and inline images each live in separate nodes. Domino converts this tree to its proprietary rich-text format by default. To access raw MIME data, you have to tell Domino to stop converting, then walk the tree with NotesMIMEEntity.
TL;DR
ConvertMIME = Falseis a prerequisite — the default True causes MIME-to-rich-text conversion;GetMIMEEntitythen returnsNothingNotesMIMEEntityrepresents one node in the MIME tree;ContentTypeandContentSubTypeidentify what it contains- Navigation:
GetFirstChildEntitydescends into children;GetNextSiblingmoves across siblings NotesMIMEHeaderrepresents one header field (e.g.Content-Type,Content-Disposition)- Available since Release 5.0.2 — supported in all current versions
- Set
ConvertMIMEback toTruewhen done — leaving itFalsecauses problems when saving documents
Getting the root MIME entity
Dim session As New NotesSessionDim db As NotesDatabaseSet db = session.CurrentDatabase
' Critical: disable auto-conversion firstsession.ConvertMIME = False
' Open a mail documentDim doc As NotesDocumentSet doc = db.GetDocumentByUNID("...")
' Get the root MIME nodeDim mime As NotesMIMEEntitySet mime = doc.GetMIMEEntity()
If mime Is Nothing Then Print "No MIME content (or ConvertMIME was still True)"Else Print "Root Content-Type: " & mime.ContentType & "/" & mime.ContentSubTypeEnd If
session.ConvertMIME = True ' RestoreA document with the item $NoteHasNativeMIME = "1" contains native MIME content.
The structure of a MIME tree
A typical HTML email with an attachment looks like this:
multipart/mixed ← root├── multipart/alternative ← child (HTML + plain-text alternative)│ ├── text/plain ← plain-text fallback│ └── text/html ← HTML body└── application/pdf ← attachmentWalk it with GetFirstChildEntity (descend) and GetNextSibling (across):
' Recursively walk the MIME treeSub WalkMIME(entity As NotesMIMEEntity, level As Integer) Dim indent As String indent = Space(level * 2) Print indent & entity.ContentType & "/" & entity.ContentSubType
Dim child As NotesMIMEEntity Set child = entity.GetFirstChildEntity() Do Until child Is Nothing Call WalkMIME(child, level + 1) Set child = child.GetNextSibling() LoopEnd Sub
' Call itsession.ConvertMIME = FalseDim mime As NotesMIMEEntitySet mime = doc.GetMIMEEntity()Call WalkMIME(mime, 0)session.ConvertMIME = TrueExtracting the body text
Once you find a text/html or text/plain node, GetContentAsText returns the decoded content:
Function GetHTMLBody(rootEntity As NotesMIMEEntity) As String If rootEntity.ContentType = "text" And rootEntity.ContentSubType = "html" Then GetHTMLBody = rootEntity.GetContentAsText() Exit Function End If ' Recurse into children Dim child As NotesMIMEEntity Set child = rootEntity.GetFirstChildEntity() Do Until child Is Nothing Dim result As String result = GetHTMLBody(child) If result <> "" Then GetHTMLBody = result Exit Function End If Set child = child.GetNextSibling() LoopEnd FunctionIdentifying attachments
An attachment node has a Content-Disposition: attachment header:
Sub ListAttachments(entity As NotesMIMEEntity) Dim dispHeader As NotesMIMEHeader Set dispHeader = entity.GetNthHeader("Content-Disposition") If Not (dispHeader Is Nothing) Then If InStr(LCase(dispHeader.HeaderVal), "attachment") > 0 Then Print "Attachment: " & entity.ContentType & "/" & entity.ContentSubType End If End If ' Recurse Dim child As NotesMIMEEntity Set child = entity.GetFirstChildEntity() Do Until child Is Nothing Call ListAttachments(child) Set child = child.GetNextSibling() LoopEnd SubReading header values
Each node’s headers are accessible through NotesMIMEHeader objects:
' Get a specific headerDim ctHeader As NotesMIMEHeaderSet ctHeader = mime.GetNthHeader("Content-Type")If Not (ctHeader Is Nothing) Then Print "Content-Type: " & ctHeader.HeaderVal Print " charset param: " & ctHeader.getParamVal("charset")End If
' Get multiple headers as a single stringDim someHeaders As StringsomeHeaders = mime.GetSomeHeaders("Content-Type, Content-Transfer-Encoding")Print someHeadersCommonly useful headers: Content-Type, Content-Disposition, Content-Transfer-Encoding, Content-ID (for inline images).
Building a MIME message from scratch with CreateMIMEEntity
The CreateMIMEEntity method on NotesDocument creates the root node:
session.ConvertMIME = False
Dim doc As NotesDocumentSet doc = db.CreateDocument()doc.Form = "Memo"doc.SendTo = "recipient@example.com"doc.Subject = "MIME test message"
' Create the root nodeDim root As NotesMIMEEntitySet root = doc.CreateMIMEEntity("Body")root.ContentType = "multipart"root.ContentSubType = "alternative"
' Add plain-text childDim textPart As NotesMIMEEntitySet textPart = root.CreateChildEntity()Call textPart.SetContentFromText("Plain text version", "text/plain;charset=UTF-8", ENC_NONE)
' Add HTML childDim htmlPart As NotesMIMEEntitySet htmlPart = root.CreateChildEntity()Call htmlPart.SetContentFromText("<p>This is the <b>HTML</b> version</p>", "text/html;charset=UTF-8", ENC_NONE)
Call doc.Save(True, False)session.ConvertMIME = TrueWhat about Java and SSJS?
| Language | Counterpart |
|---|---|
| LotusScript | NotesMIMEEntity / NotesMIMEHeader |
| Java | lotus.domino.MIMEEntity / MIMEHeader (drop the Notes prefix; .recycle() when done) |
| SSJS | MIMEEntity / MIMEHeader (callable in XPages, same API surface) |