C# 将文件(pdf、word 等)作为附加文件添加到 onenote 页面

C# Adding a file (pdf,word, ect..) to a onenote page as Attach File

提问人:Dimitry Okken 提问时间:4/6/2023 最后编辑:Dimitry Okken 更新时间:4/13/2023 访问量:231

问:

我正在尝试在我的 .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);
                        });
Outlook 拖放 html-email 电子邮件附件 OneNote

评论

0赞 Dimitry Okken 4/7/2023
我已经更新了原始帖子。 电子邮件正文中的内联图像现在与其他所有内容一起推送到 onenote 页面。仍然需要解决的是非内联的附件。这些文件需要附加到字符串 emailbody 中位于 {insertedFiles} 的页面。Outlook 插件“发送到 OneNote”的执行方式相同。查看原始帖子中的 2 张图片
0赞 Eugene Astafiev 4/11/2023
与其编辑原始帖子,我建议标记答案并在新线程中发布新的具体问题,以便读者可以轻松识别问题和答案。

答:

0赞 Eugene Astafiev 4/7/2023 #1

听起来您只需要为附加的文件附加一个图像,并在需要时(在表格单元格中)显示在邮件正文中。以下代码演示如何附加图像,然后在邮件正文中设置对它的引用:

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_IDPT_ATTACH_HIDDENhttp://schemas.microsoft.com/mapi/proptag/0x7FFE000B

Outlook 不支持 base64 图像,您需要改为处理附加的项目。所以下面的代码段没有任何意义:

emailBody = emailBody.Replace($"cid:{cid}", $"data:image/png;base64,{base64String}");

附加的项目使用属性设置为 CID 值的元素显示在消息正文中(见上文)。<a>src

评论

0赞 Dimitry Okken 4/7/2023
我试图完成的是 1) 电子邮件中的内联图像与电子邮件正文的其余部分(文本)一起推送到 onenote 页面,位于正文中的正确位置,就像在电子邮件中一样。因此,OneNote 页面内容是邮件正文的一对一副本 2) 附加(非内联)到电子邮件的文件(Word、PDF、Excel 等)需要推送到 OneNote 并添加为所述文件/附件的副本。这个文件需要放在表中@ {insertedFiles}
0赞 Eugene Astafiev 4/11/2023
您可以通过检查属性中 CID 前缀的 HTML 标记(请参阅属性)来识别内联附件(嵌入图像)。HTMLBodysrc
0赞 Dimitry Okken 4/11/2023
emailBody = emailBody.Replace($"cid:{cid}", $"data:image/png;base64,{base64String}");对于 OneNote 来说似乎是必要的。我正在将电子邮件正文推送到 onenote。我正在从 outlook 中检索,但没有向它推送任何东西。使用此行,mailItem.HTMLBody 中的内联图像将被转换,以便 onenote 识别它,如果没有它,我似乎无法显示任何内联图像。
0赞 Eugene Astafiev 4/12/2023
我建议标记答案并在新线程中发布新的特定问题,以便读者可以轻松识别问题和答案。
0赞 Dimitry Okken 4/13/2023 #2

编辑/更新 2:

我还解决了第二个问题,实际上并不是很复杂,见下文。这会将 Outlook 文件附件作为文件附件添加到 onenote 页面。仍然需要重写整个 Dragdrop 方法......更好!

  1. 一般代码编写:健壮性、最佳实践、异常/错误处理
  2. 文件附件放在页面上的位置
  3. Beter 处理邮件中的多个文件附件。不过,当前的方式确实适用于多个附件(很好)。
  4. 可选:附件直接从邮件项目中拉取,而不是保存到临时位置,否则清理临时位置。
 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 中启用一个复选框,并“灰显”这些列表视图中的项目...