提问人:Dimitry Okken 提问时间:4/6/2023 最后编辑:Dimitry Okken 更新时间:4/13/2023 访问量:231
C# 将文件(pdf、word 等)作为附加文件添加到 onenote 页面
C# Adding a file (pdf,word, ect..) to a onenote page as Attach File
问:
我正在尝试在我的 .net 6.0 c# 应用程序中制作一种 outlook“发送到 onenote”插件(作为拖放)。 到目前为止,电子邮件的整个正文(从读取 Outlook 收件箱/发件箱的 listView 拖动)作为新页面推送到 onenote(listviewArchive 包含带有 .one 文件的文件夹)。唯一的问题是,我似乎无法弄清楚如何将附件(不是内联,而是文件作为 MailItem 中的附件)添加到 OnenNote 页面,就像 Outlook“发送到 Onennote”一样。在这里输入图片描述,在这里输入图片描述。我用于将电子邮件推送到 onenote 的代码是
using Onenote = Microsoft.Office.Interop.OneNote;
private async void listViewArchive_DragDrop(object sender, DragEventArgs e)
{
Point clientPoint = listViewArchive.PointToClient(new Point(e.X, e.Y));
ListViewItem targetItem = listViewArchive.GetItemAt(clientPoint.X, clientPoint.Y);
Onenote.Application onenoteApp = new Onenote.Application();
if (targetItem != null && e.Data.GetDataPresent(typeof(ListView.SelectedListViewItemCollection)))
{
ViewReadOnly = false;
string targetPath = (string)targetItem.Tag;
string folderName = draggedFrom ? "in.one" : "out.one";
targetPath = Path.Combine(targetPath, folderName);
if (!File.Exists(targetPath))
{
MessageBox.Show("No section file found, Mailwill not be added as a page", "File not found", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
Marshal.ReleaseComObject(onenoteApp);
onenoteApp= null;
return;
}
ListView.SelectedListViewItemCollection selectedItems = (ListView.SelectedListViewItemCollection)e.Data.GetData(typeof(ListView.SelectedListViewItemCollection));
foreach (ListViewItem item in selectedItems)
{
if (item.Tag is Outlook.MailItem mailItem)
{
string m_xmlNewOutlineContent =
"<one:Meta name=\"{2}\" content=\"{1}\"/>" +
"<one:OEChildren><one:HTMLBlock><one:Data><![CDATA[{0}]]></one:Data></one:HTMLBlock></one:OEChildren>";
string m_xmlNewOutline =
"<?xml version=\"1.0\"?>" +
"<one:Page xmlns:one=\"{2}\" ID=\"{1}\">" +
"<one:Outline>{0}</one:Outline></one:Page>";
string m_outlineIDMetaName = "Outlook Email To OneNote AddIn ID";
string m_xmlns = "http://schemas.microsoft.com/office/onenote/2013/onenote";
await Task.Run(() =>
{
string subject = mailItem.Subject;
string from = mailItem.SenderName;
string to = mailItem.To;
string cc = mailItem.CC;
DateTime sentTime = mailItem.SentOn;
string attachments = "";
List<string> attachmentPaths = new List<string>();
foreach (Outlook.Attachment attachment in mailItem.Attachments)
{
bool isInline = false;
try
{
isInline = (bool)attachment.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x7FFE000B");
}
catch (Exception)
{
// still to add....
}
if (!isInline)
{
string attachmentPath = Path.Combine(Path.GetTempPath(), attachment.FileName);
attachment.SaveAsFile(attachmentPath);
attachmentPaths.Add(attachmentPath);
attachments += attachment.FileName + ";";
}
}
string insertedFiles = string.Empty;
foreach (string attachmentPath in attachmentPaths)
{
//code to add the files to the table in string emailBody, no idea how....
}
string emailBody =
"<table border=\"1\" cellpadding=\"5\"><tr><th>Subject</th><th>From</th><th>To</th><th>CC</th><th>Sent Time</th><th>Attachments</th></tr>" +
$"<tr><td>{subject}</td><td>{from}</td><td>{to}</td><td>{cc}</td><td>{sentTime}</td><td>{insertedFiles}</td></tr></table>" +
mailItem.HTMLBody;
// Create new OneNote page and insert email content
string xmlHierarchy;
onenoteApp.GetHierarchy("", HierarchyScope.hsSections, out xmlHierarchy);
string targetID = string.Empty;
onenoteApp.OpenHierarchy(targetPath, string.Empty, out targetID);
onenoteApp.CreateNewPage(targetID, out string pageID, NewPageStyle.npsBlankPageWithTitle);
int outlineID = new Random().Next();
string outlineContent = string.Format(m_xmlNewOutlineContent, emailBody, outlineID, m_outlineIDMetaName);
string xml = string.Format(m_xmlNewOutline, outlineContent, pageID, m_xmlns);
// Get the title and set it to our page name
onenoteApp.GetPageContent(pageID, out xml, PageInfo.piAll);
XNamespace ns = null;
var doc = XDocument.Parse(xml);
ns = doc.Root.Name.Namespace;
var title = doc.Descendants(ns + "T").First();
title.Value = subject;
// Update the page to add pagetitle/pagename
onenoteApp.UpdatePageContent(doc.ToString());
// Update the page again to add the actual body of the mailitem
onenoteApp.UpdatePageContent(xml, DateTime.MinValue);
});
}
}
}
Marshal.ReleaseComObject(onenoteApp);
onenoteApp= null;
}
它处理内联图像并不总是正确。我花了很多互联网搜索和复制/粘贴才能到达这个 piont,但是...... 如果有人可以添加到代码中以处理附件,并且可以查看 MailItem 正文中的内联图像,那就太好了!我没有足够的知识来弄清楚这个问题......
做了很多,但没有保持这一点。然后迷路了。在 stackoverflow 中搜索了很多,但找不到任何东西......
编辑/更新 1:
问题 2) 附加尚未解决的文件。有什么帮助吗?
问题 1:“内联图像”看起来已解决。我在“await Task.Run(()”中移动了一些东西。 现在,内联图像将添加到 OneNote 正文中。我将 foreach(mailItem.Attachments 中的 Outlook.Attachment 附件)移动到“字符串 emailBody”下方,并添加了 else if (isInline) 代码块。foreach 循环现在通过转换和替换内联图像以正确的方式更新“string emailBody”。电子邮件的内嵌图像现在显示在 OneNote 页面上
await Task.Run(() =>
{
string subject = mailItem.Subject;
string from = mailItem.SenderName;
string to = mailItem.To;
string cc = mailItem.CC;
DateTime sentTime = mailItem.SentOn;
string attachments = "";
string insertedFiles = string.Empty;
string emailBody =
"<table border=\"1\" cellpadding=\"5\"><tr><th>Subject</th><th>From</th><th>To</th><th>CC</th><th>Sent Time</th><th>Attachments</th></tr>" +
$"<tr><td>{subject}</td><td>{from}</td><td>{to}</td><td>{cc}</td><td>{sentTime}</td><td>{insertedFiles}</td></tr></table>" +
mailItem.HTMLBody;
List<string> attachmentPaths = new List<string>();
foreach (Outlook.Attachment attachment in mailItem.Attachments)
{
bool isInline = false;
try
{
isInline = (bool)attachment.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x7FFE000B");
}
catch (Exception)
{
}
if (!isInline)
//saving them mfirst on temp location is just to see if i am able to get the files
{
string attachmentPath = Path.Combine(Path.GetTempPath(), attachment.FileName);
attachment.SaveAsFile(attachmentPath);
attachmentPaths.Add(attachmentPath);
attachments += attachment.FileName + ";";
}
else if (isInline)
{
byte[] attachmentData = (byte[])attachment.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x37010102");
// Convert the binary data to a base64 string
string base64String = Convert.ToBase64String(attachmentData);
// Replace the inline image tag with the base64 encoded string
string cid = attachment.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001E") as string;
emailBody = emailBody.Replace($"cid:{cid}", $"data:image/png;base64,{base64String}");
}
}
foreach (string attachmentPath in attachmentPaths)
{
//still needs solving. the save files need to be added to the onenote page as attached file
//but it seems redonned to first save the email attached file and the grapping them form temp location.
//so be able to get them form mail directly
}
// Create new OneNote page and insert email content
string xmlHierarchy;
onenoteApp.GetHierarchy("", HierarchyScope.hsSections, out xmlHierarchy);
string targetID = string.Empty;
onenoteApp.OpenHierarchy(targetPath, string.Empty, out targetID);
onenoteApp.CreateNewPage(targetID, out string pageID, NewPageStyle.npsBlankPageWithTitle);
int outlineID = new Random().Next();
string outlineContent = string.Format(m_xmlNewOutlineContent, emailBody, outlineID, m_outlineIDMetaName);
string xml = string.Format(m_xmlNewOutline, outlineContent, pageID, m_xmlns);
// Get the title and set it to our page name
onenoteApp.GetPageContent(pageID, out xml, PageInfo.piAll);
XNamespace ns = null;
var doc = XDocument.Parse(xml);
ns = doc.Root.Name.Namespace;
var title = doc.Descendants(ns + "T").First();
title.Value = subject;
// Update the page to add pagetitle/pagename
onenoteApp.UpdatePageContent(doc.ToString());
outlineContent = string.Format(m_xmlNewOutlineContent,emailBody, outlineID, m_outlineIDMetaName);
xml = string.Format(m_xmlNewOutline, outlineContent, pageID, m_xmlns);
// Update the page again to add the actual body of the mailitem
onenoteApp.UpdatePageContent(xml, DateTime.MinValue);
});
答:
听起来您只需要为附加的文件附加一个图像,并在需要时(在表格单元格中)显示在邮件正文中。以下代码演示如何附加图像,然后在邮件正文中设置对它的引用:
Attachment attachment = newMail.Attachments.Add(@"E:\Pictures\image001.jpg", OlAttachmentType.olEmbeddeditem, null, "Some image display name");
string imageCid = "image@123";
attachment.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001E", imageCid);
newMail.HTMLBody = String.Format("<body><img src=\"cid:{0}\"></body>", imageCid);
基本上,您需要在附件上设置属性,然后在正文中引用它。此外,如果要从视图中隐藏附加的文件,还可以考虑设置属性(DASL 名称为 )。PR_ATTACH_CONTENT_ID
PT_ATTACH_HIDDEN
http://schemas.microsoft.com/mapi/proptag/0x7FFE000B
Outlook 不支持 base64 图像,您需要改为处理附加的项目。所以下面的代码段没有任何意义:
emailBody = emailBody.Replace($"cid:{cid}", $"data:image/png;base64,{base64String}");
附加的项目使用属性设置为 CID 值的元素显示在消息正文中(见上文)。<a>
src
评论
HTMLBody
src
emailBody = emailBody.Replace($"cid:{cid}", $"data:image/png;base64,{base64String}");
对于 OneNote 来说似乎是必要的。我正在将电子邮件正文推送到 onenote。我正在从 outlook 中检索,但没有向它推送任何东西。使用此行,mailItem.HTMLBody 中的内联图像将被转换,以便 onenote 识别它,如果没有它,我似乎无法显示任何内联图像。
编辑/更新 2:
我还解决了第二个问题,实际上并不是很复杂,见下文。这会将 Outlook 文件附件作为文件附件添加到 onenote 页面。仍然需要重写整个 Dragdrop 方法......更好!
- 一般代码编写:健壮性、最佳实践、异常/错误处理
- 文件附件放在页面上的位置
- Beter 处理邮件中的多个文件附件。不过,当前的方式确实适用于多个附件(很好)。
- 可选:附件直接从邮件项目中拉取,而不是保存到临时位置,否则清理临时位置。
if (!isInline)
{
string attachmentPath = Path.Combine(Path.GetTempPath(), attachment.FileName);
attachment.SaveAsFile(attachmentPath);
//enclose the file in the correct onenote node
attachments += string.Format("<one:InsertedFile pathSource=\"{0}\" preferredName=\"{1}\" />", attachmentPath, attachment.FileName);
//update string incase this if statement is invoked
m_xmlNewOutline =
"<?xml version=\"1.0\"?>" +
"<one:Page xmlns:one=\"{2}\" ID=\"{1}\">" +
$"{attachments}"+
"<one:Outline>{0}" +
"</one:Outline></one:Page>";
//still need to look at handling multiple fileattachments...
}
但至少上面的代码允许将多个 Outlook 文件附件附加到 onenote 页面。整个 DragDrop 方法还包括一个自定义进度条的实例,该实例由我制作,用于指示某些内容正在复制到/保存到 onenote,并且 mailitem 本身获取一个自定义属性,该属性指示 mailitem 已存档到 onenote。这会在 listviewInbox/Outbox 中启用一个复选框,并“灰显”这些列表视图中的项目...
评论