Dimitry Okken
Dimitry Okken

Reputation: 1

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

I am trying to make sort of a outlook "send to onenote" plugin (as a drag and drop) in my .net 6.0 c# app. i am as far that the entire body of the email (dragged from a listview that reads outlook inbox/outbox) is pushed to onenote as a new page (listviewArchive contains folders with .one files). the only problem is that I can not seem to figure out how to add the attachments (not inline,but files as attachments in mailitem) to the onennote page the same way the outlook "sent to onennote" does it.enter image description here and mine enter image description here. the code I am using to push the email to onenote is

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;
        }

it handles inline image not always correctly to. took me a lot of internet searches and copy/paste to get to this piont but... if anybody could add to the code to handle the attachments and maybe look at inline images that are in the mailitem's body, that would be great! I do not have enough knowledge to figure this one out....

did a lot but did not keep this. and got lost. search alot in stackoverflow but could not find anything for this...


Edit/Update 1:

problem 2) Attach files not yet solved. any help?

problem 1 "inline images" looks solved. I moved some things around in "await Task.Run(()". now the inline images are added to the onenote body. I moved the foreach (Outlook.Attachment attachment in mailItem.Attachments) below the "string emailBody" and added else if (isInline) code block. the foreach loop is now updating "string emailBody" with the inline images the correct way by converting them and replacing. the inline image of the email are now displayed on the onenote page

    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);
                        });

Upvotes: 0

Views: 369

Answers (2)

Dimitry Okken
Dimitry Okken

Reputation: 1

Edit/Update 2:

I also solved the second problem and wasn't actually very complicated, see below. This adds the outlook file attachments as file attachments to the onenote page. Still need rewrite the entire Dragdrop methode to be....better!

  1. General code writing: robustness, best practice, exception/error handling
  2. Where the file attachment is put on the page itself
  3. Beter handling of multiple file attachments in a mail. Current way does work (fine) with multiple attachment though.
  4. Optional: attachment is pulled directly from the mailitem and not saved to a temp location, otherwise clean up temp location.
 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... 
 }

But atleast the code above enables the attaching of multiple outlook file attachment to onenote page. The entire DragDrop method also includes an instance of a custom progressbar I made to indicate something is copying to/saved to onenote and the mailitem itself gets a custom property that indicates mailitem is archived to onenote. this enables in a listviewInbox/Outbox a checkbox and "greying out" of the item in these listviews...

Upvotes: 0

Eugene Astafiev
Eugene Astafiev

Reputation: 49455

Sounds like you just need to attach an image for the file attached and display in the message body where required (in the table cell). The following code shows how to attach an image and then set a reference to it in the message body:

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);

You basically need to set up the PR_ATTACH_CONTENT_ID property on the attached file and then reference it in the body. Also if you want to hide the attached file from the view you may also consider setting the PT_ATTACH_HIDDEN property (the DASL name is http://schemas.microsoft.com/mapi/proptag/0x7FFE000B).

Outlook doesn't support base64 images, you need to deal with attached items instead. So the following piece of code doesn't make any sense:

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

The attached item is displayed in the message body using the <a> element where the src attribute is set to the CID value (see above).

Upvotes: 0

Related Questions