Attachments in LotusScript: EmbedObject, NotesEmbeddedObject, and the GetAttachment Shortcut
An agent needs to attach a generated PDF to a document and mail it; another needs to sweep incoming documents, pull every attachment to a network folder, and delete the originals. Both are everyday jobs, and both run through one class — NotesEmbeddedObject — plus a couple of methods on NotesRichTextItem and NotesDocument. The API carries some OLE-era baggage, so the trick is knowing which parts still matter.
TL;DR
- A
NotesEmbeddedObject“represents any one of the following: An embedded object, An object link, A file attachment.” For modern work, file attachments are the case that matters — OLE embedding/linking is Windows-only legacy. - Attach a file:
Set eo = rtitem.EmbedObject(EMBED_ATTACHMENT, "", "c:\path\file.pdf"). The type constants areEMBED_ATTACHMENT(1454),EMBED_OBJECT(1453),EMBED_OBJECTLINK(1452). - Find one attachment by name:
doc.GetAttachment(fileName$)— it finds the attachment regardless of which rich text item holds it (or none), which is its whole point. - Extract to disk:
Call eo.ExtractFile(path$)— attachments only; it errors on OLE objects/links, so always gate oneo.Type = EMBED_ATTACHMENT. - Trap:
NotesDocument.EmbeddedObjects“does not return file attachments” — iteratertitem.EmbeddedObjects(per rich text item) or useGetAttachmentinstead. doc.HasEmbeddedis a quick Boolean check for “does this document carry anything attached/embedded.”
Attaching a file
EmbedObject lives on the rich text item. For a plain file attachment, the type is EMBED_ATTACHMENT, the class string is empty, and the source is the path to the file:
Dim session As New NotesSessionDim db As NotesDatabaseDim doc As NotesDocumentDim rtitem As NotesRichTextItemDim eo As NotesEmbeddedObjectSet db = session.CurrentDatabaseSet doc = New NotesDocument(db)Set rtitem = New NotesRichTextItem(doc, "Body")Set eo = rtitem.EmbedObject(EMBED_ATTACHMENT, "", "c:\reports\q1.pdf")doc.Form = "Main Topic"doc.Subject = "Here's the Q1 report, attached"Call doc.Save(True, True)That snippet is the official example (with the file path updated). The optional fourth name$ argument applies only to OLE objects, not attachments, so you leave it off here. One requirement from the docs: the database needs a default view set for EmbedObject to work.
Finding attachments — and the EmbeddedObjects trap
There are three ways to reach attached files, and the difference between them is the part worth memorising:
doc.HasEmbedded— read-only Boolean,Trueif the document has anything embedded, linked, or attached. A cheap gate before you do more work.doc.GetAttachment(fileName$)— returns theNotesEmbeddedObjectfor a named attachment, orNothing. Its strength, per the docs, is that it finds “file attachments which are not contained in a rich text item… as well as file attachments that are contained in a rich text item.” So you don’t need to know where the file is attached. (Caveat: the returned object’sParentisNothing, since you didn’t reach it through a rich text item.)rtitem.EmbeddedObjects— the array of embedded objects in that rich text item, which does include file attachments.
The trap is the fourth option people reach for first: doc.EmbeddedObjects. The class page is explicit that the document-level version “does not return file attachments” — so a loop over doc.EmbeddedObjects silently skips exactly the thing you’re usually after. Use the rich-text-item array or GetAttachment.
Extracting and removing
To pull attachments to disk, iterate the rich text item’s objects, gate on the attachment type, and call ExtractFile. This is the official pattern:
Dim doc As NotesDocumentDim rtitem As VariantDim fileCount As IntegerConst MAX = 100000fileCount = 0'...set value of doc...Set rtitem = doc.GetFirstItem("Body")If (rtitem.Type = RICHTEXT) Then Forall o In rtitem.EmbeddedObjects If (o.Type = EMBED_ATTACHMENT) And (o.FileSize > MAX) Then fileCount = fileCount + 1 Call o.ExtractFile("c:\reports\newfile" & Cstr(fileCount)) Call o.Remove Call doc.Save(True, True) End If End ForallEnd IfTwo things to carry into production from this official snippet. First, the o.Type = EMBED_ATTACHMENT guard isn’t optional — ExtractFile raises an error on OLE objects and object links, so extracting without the check will blow up the moment a document has a non-attachment embedded object. Second, note the extracted names (newfile1, newfile2…) have no extension — that’s an HCL-example quirk; in real code extract with the original name or a real extension so the file opens.
o.Remove deletes the attachment, and (like all rich-text edits) the change isn’t persisted until doc.Save. Useful NotesEmbeddedObject properties along the way: Name, FileSize (bytes, for attachments), Type, Class and Verbs (OLE only), and Source.
What about Java and SSJS?
| LotusScript | Java | SSJS / XPages |
|---|---|---|
NotesEmbeddedObject | EmbeddedObject | EmbeddedObject |
NotesRichTextItem.EmbedObject | RichTextItem.embedObject | RichTextItem.embedObject |
The Java and SSJS surfaces mirror this — rtitem.embedObject(...), doc.getAttachment(...), eo.extractFile(...), the same EMBED_ATTACHMENT constant and the same “document-level getEmbeddedObjects() omits attachments” behaviour. The advice carries across unchanged: reach attachments through getAttachment or the rich-text item, not the document-level collection.