如何正确添加和删除 MIME 附件
Posted
技术标签:
【中文标题】如何正确添加和删除 MIME 附件【英文标题】:How to Add and Remove MIME attachments correctly 【发布时间】:2019-04-25 03:59:48 【问题描述】:我正在向这样的文档添加 MIME 附件
try
var d = database.getView("Main").getFirstDocument()
var it = d.getFirstItem("Body")
var att:NotesEmbeddedObject = it.getEmbeddedObject("mydoc.docx")
var streamDOC:NotesStream = session.createStream()
streamDOC.setContents(att.getInputStream())
var newd;
newd = database.getView("NewD").getFirstDocument()
if(newd==null)
newd = database.createDocument()
newd.replaceItemValue("Form","Main")
var me = newd.createMIMEEntity("Body")
else
var me = newd.getMIMEEntity("Body")
var filename = "test.pdf"
var mc = me.createChildEntity();
var he = mc.createHeader("Content-Disposition")
he.setHeaderVal("attachment; filename=\"" + filename + "\"");
he = mc.createHeader("Content-ID");
he.setHeaderVal( "<" + filename + ">" );
mc.setContentFromBytes(streamDOC, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", NotesMIMEEntity.ENC_IDENTITY_8BIT);
newd.save()
print("success")
catch(e)
print("fail " + e)
我提供了一个删除按钮
var eo = nd.getDocument().getAttachment(att)
eo.remove()
nd.save()
附件已从文档中删除,在 Ytria 中,我可以看到 $FILE 项目已删除,但 BODY 项目未删除。这样做的问题是,如果我在同一个文档中添加一个新附件,我之前删除的所有附件都会回来
这是删除附件之前文档的外观。
不幸的是,这里的文件大小为 0Kb,因为我使用了错误的屏幕截图。从一开始所有的 $File 项目都有正确的大小
这是我删除附件后文档的外观(使用上面的脚本)
这是我删除附件后添加一个附件(使用上面的脚本)后文档的样子
添加或删除附件时我做错了什么吗? (看 脚本) Body 字段是否有“商店”似乎无关紧要 内容为 MIME”选项设置与否 另请参阅此问题 How to Add and Remove attachments using MIME【问题讨论】:
【参考方案1】:如果您使用 MIME 方法来附加文件,为什么不使用 MIME 方法来删除它呢?
我使用自己的框架,因此以下代码可能会让您觉得事情过于复杂,但希望您能明白其中的要点:
我有一个枚举,可以帮助我浏览各种 MIME 类型。在这种情况下,您正在处理ATTACHMENT
:
public enum MimeContentType
ATTACHMENT("attachment")
@Override
public boolean matches(String[] headers)
int score = 0;
for (String header : headers)
if (header.startsWith("Content-Disposition"))
score++;
if (header.contains("attachment"))
score++;
if (header.contains("filename"))
score++;
if (score == 3)
return true;
return false;
,
TEXT("text"),
TEXT_html("text/html"),
TEXT_PLAIN("text/plain");
private final String type;
private MimeContentType(String type)
this.type = type;
public boolean matches(String[] headers)
for (String header : headers)
if (header.startsWith("Content-Type") && header.contains(type))
return true;
return false;
然后是一些辅助类:
@FunctionalInterface
public interface ThrowableConsumer<T> extends Consumer<T>
@Override
default void accept(final T t)
try
acceptOrThrow(t);
catch (final Throwable e)
throw new RuntimeException(e);
void acceptOrThrow(T t) throws Throwable;
@FunctionalInterface
public interface ThrowableFunction<T, R> extends Function<T, R>
@Override
default R apply(T t)
try
return applyOrThrow(t);
catch (final Throwable e)
throw new RuntimeException(e);
R applyOrThrow(T t) throws Throwable;
@FunctionalInterface
public interface ThrowablePredicate<T> extends Predicate<T>
@Override
default boolean test(T t)
try
return testOrThrow(t);
catch (final Throwable e)
throw new RuntimeException(e);
boolean testOrThrow(T t) throws Throwable;
@FunctionalInterface
public interface ThrowableSupplier<T> extends Supplier<T>
@Override
default T get()
try
return getOrThrow();
catch (final Throwable e)
throw new RuntimeException(e);
T getOrThrow() throws Throwable;
public enum DominoUtil
;
private static final Vector<String> MIME_FILTERED_HEADERS = new Vector<>();
static
MIME_FILTERED_HEADERS.add("Content-Type");
MIME_FILTERED_HEADERS.add("Content-Disposition");
public static List<MIMEEntity> getMimeEntitiesByContentType(MIMEEntity entity,
MimeContentType contentType) throws NotesException
Objects.requireNonNull(entity, "Entity cannot be null");
Objects.requireNonNull(contentType, "Content type cannot be null");
List<MIMEEntity> subentities = new ArrayList<>();
MIMEEntity nextEntity = null;
try
nextEntity = entity.getNextEntity();
while (nextEntity != null)
String[] entityFilteredHeaders = nextEntity
.getSomeHeaders(MIME_FILTERED_HEADERS, true)
.split("\\n");
if (contentType.matches(entityFilteredHeaders))
subentities.add(nextEntity);
nextEntity = nextEntity.getNextEntity();
finally
DominoUtil.recycle(nextEntity);
return subentities;
public final static MIMEEntity getMimeEntity(Document doc, String itemName,
boolean createOnFail) throws NotesException
if (itemName == null)
throw new NullPointerException("Invalid MIME entity item name");
MIMEEntity mimeEntity = doc.getMIMEEntity(itemName);
if (mimeEntity == null)
if (doc.hasItem(itemName))
doc.removeItem(itemName);
if (createOnFail)
mimeEntity = doc.createMIMEEntity(itemName);
return mimeEntity;
public static Optional<String> getMimeEntityAttachmentFilename(MIMEEntity entity) throws NotesException
Objects.requireNonNull(entity, "Entity cannot be null");
return getMimeEntityHeaderValAndParams(
entity, (ThrowablePredicate<MIMEHeader>) h -> h.getHeaderVal().equals("attachment"))
.map(s ->
Matcher m = Pattern.compile("filename=['\"]?([^'\"\\s]+)").matcher(s);
m.find();
return m.group(1);
);
public static Optional<String> getMimeEntityHeaderValAndParams(
MIMEEntity entity, Predicate<MIMEHeader> matcher) throws NotesException
Objects.requireNonNull(entity, "Entity cannot be null");
Objects.requireNonNull(matcher, "Matcher cannot be null");
Vector<?> headers = entity.getHeaderObjects();
try
return headers
.stream()
.map(MIMEHeader.class::cast)
.filter(matcher)
.map((ThrowableFunction<MIMEHeader, String>) MIMEHeader::getHeaderValAndParams)
.findFirst();
finally
recycle(headers);
public static void recycle(Base... bases)
for (Base base : bases)
if (base != null)
try
base.recycle();
catch (Exception e)
// Do nothing
public static void recycle(Collection<? extends Object> objs)
objs.stream()
.filter(o -> o instanceof Base)
.map(o -> (Base) o)
.forEach(DominoUtil::recycle);
最后是可以完成这项工作的方法:
public class Example
public static void yourEntryPoint()
try
// The last param is just a way to create an attachment from text
// You have InputStream to pass along obviously
addAttachment(doc, "Body", "fake1.txt", "this is fake text1");
addAttachment(doc, "Body", "fake2.txt", "this is fake text2");
addAttachment(doc, "Body", "fake3.txt", "this is fake text3");
removeAttachment(doc, "Body", "fake2.txt");
removeAttachment(doc, "Body", "fake3.txt");
catch (NotesException e)
throw new RuntimeException(e);
private static void addAttachment(Document doc, String itemName, String fileName, String data)
throws NotesException
MIMEEntity mimeEntity = null;
Stream stm = null;
try
mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);
Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);
MIMEEntity attachmentEntity = null;
if (optAttEntity.isPresent())
attachmentEntity = optAttEntity.get();
else
attachmentEntity = mimeEntity.createChildEntity();
MIMEHeader header = attachmentEntity.createHeader("Content-Disposition");
header.setHeaderValAndParams("attachment; filename=\"" + fileName + "\"");
stm = doc.getParentDatabase().getParent().createStream();
stm.writeText(data);
attachmentEntity.setContentFromBytes(stm,
"application/octet-stream",
MIMEEntity.ENC_IDENTITY_BINARY);
stm.close();
doc.closeMIMEEntities(true, itemName);
finally
DominoUtil.recycle(stm);
DominoUtil.recycle(mimeEntity);
private static void removeAttachment(Document doc, String itemName, String fileName)
throws NotesException
MIMEEntity mimeEntity = null;
try
// Get MIME entity
mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);
Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);
if (!optAttEntity.isPresent())
return;
optAttEntity.get().remove();
// Header cleaning on empty entity
if (mimeEntity.getFirstChildEntity() != null)
doc.closeMIMEEntities(true, itemName);
else
mimeEntity.remove();
finally
DominoUtil.recycle(mimeEntity);
private static Optional<MIMEEntity> getAttachmentMimeEntity(MIMEEntity root, String fileName)
throws NotesException
return DominoUtil
.getMimeEntitiesByContentType(root, MimeContentType.ATTACHMENT)
.stream()
.filter((ThrowablePredicate<MIMEEntity>) mime ->
Optional<String> opt = DominoUtil.getMimeEntityAttachmentFilename(mime);
return opt.isPresent() && opt.get().equals(fileName);
)
.findFirst();
【讨论】:
谢谢,这可能会有所帮助,但您的代码不完整 public static Map以上是关于如何正确添加和删除 MIME 附件的主要内容,如果未能解决你的问题,请参考以下文章
您将使用啥架构来存储 100 亿条 MIME 消息并使其可删除和全文搜索,包括。附件
如何编写多部分 MIME 混合消息以在 Outlook 中正确显示