0

I have an Outlook AddIn that handles the addition of attachments to an email by providing an addAttachment() handler and inserting hyperlinks into the body of the email for each attached file.

Inserting the hyperlink is no problem but if the attachments are added by dragging them into the email, the insert cursor always remains just before the hyperlink(s).

                Document doc = currentMailItem.GetInspector.WordEditor;
                Selection objSel = doc.Windows[1].Selection;
                Range insertRange = objSel.Range;
                object missObj = Type.Missing;
                Hyperlink link = doc.Hyperlinks.Add(insertRange, MyUrl, missObj, missObj, displayName, missObj);
                objSel.Collapse(WdCollapseDirection.wdCollapseEnd);
                /* also tried this:
                Range r = link.Range;
                objSel.MoveRight(WdUnits.wdCharacter, r.End, r.Start);
                 * */

I suspect that my problem may be the drag&drop handling. I have noticed that the cursor appears where I placed it, after the inserted Url, but then jumps back to the point just before it. Could it be that when completing the drag&drop operation that something is resetting the cursor to its original location?

Can someone give me a clue as to what I need to do?

B. Leslie
  • 165
  • 10

1 Answers1

0

I have created a project very similar to this in the past and opted to use the MailItem.HTMLBody property instead of fighting with object placement.

In my case I was constructing a data grid, but something similar can be constructed to take in your URL data. NOTE: This was early in my development days and the code may need some refactoring, but for a copy and paste from the past, it isn't too bad I hope. I have also excluded some unnecessary information from this post, but the most important bits are contained herein.

In order to assemble the body of the email, this method creates a StringBuilder and constructs the HTML document piece by piece.

        public string ConstructBody(DataTable dataTable)
        {
            StringBuilder bodyStringBuilder = new StringBuilder();

            // Creates the HTML code, constructs body, Constructs table, defines table border.
            bodyStringBuilder.AppendLine("<html>");
            bodyStringBuilder.AppendLine(Tab + "<body>");
            bodyStringBuilder.AppendLine(Tab + Tab + "<table>");
            bodyStringBuilder.AppendLine(Tab + Tab + "<table border='2' bgcolor:#DDDDDD bordercolor:black>");

            // Column headers - Style defined.
            bodyStringBuilder.Append(Tab + Tab + Tab + "<tbody align='center' style='font-family:verdana; color:#000000; font-size:14;background-color:#9DB9C8'>");
            bodyStringBuilder.Append(Tab + Tab + Tab + "<tr>");

            // Column Headers - Named 
            foreach (DataColumn dc in dataTable.Columns)
            {
                bodyStringBuilder.AppendFormat("<th>{0}</th>", dc.ColumnName);
            }

            // End of Column Header Creation
            bodyStringBuilder.AppendLine("</tr>");

            // Empty data rows created and filled by another foreach loop
            int drColorSwitch = 1;

            foreach (DataRow dr in dataTable.Rows)
            {
                if (IsOdd(drColorSwitch))
                {
                    bodyStringBuilder.Append(Tab + Tab + Tab + Tab + "<tbody align='center' style='font-family:verdana;background-color=#DDDDDD; color:#000000; font-size:14 '>");
                }
                else
                {
                    bodyStringBuilder.Append(Tab + Tab + Tab + Tab + "<tbody align='center' style='font-family:verdana;background-color=#BDD0D9; color:#000000; font-size=14 '>");
                }
                bodyStringBuilder.Append(Tab + Tab + Tab + "<tr>");
                drColorSwitch ++;

                // Fills the data. 
                foreach (DataColumn dc in dataTable.Columns)
                {
                    string cellValue = dr[dc] != null ? dr[dc].ToString() : "";
                    bodyStringBuilder.AppendFormat("<td>{0}</td>", cellValue);
                }

                // Closes out each datarow
                bodyStringBuilder.AppendLine("</tr>");
            }  // End of the datarow creation functions

            // Closes the table, closes the body, and finally ends the HTML code for the body of the email. 
            bodyStringBuilder.AppendLine(Tab + Tab + "</table>");
            bodyStringBuilder.AppendLine(Tab + "</body>");
            bodyStringBuilder.AppendLine("</html>");

            return bodyStringBuilder.ToString();                               // Finally - returns value of SB
        }

Finally, in the MailReport method I create the email message and call Send();

public void MailReport(DataTable datatable,string[] recipients,string subject, string headertext, string reporttitle, bool includedate, bool includefiles, string[] filelist, bool isEncrypted)
        {
            // Creates instance of Header and Body Construction Classes
            HeaderConstruction headerConstruction = new HeaderConstruction(); 
            BodyConstruction bodyConstruction = new BodyConstruction();


            Outlook.Application oApp = new Outlook.Application();
            Outlook.MailItem oMsg = oApp.CreateItem(Outlook.OlItemType.olMailItem);
            foreach (string recipient in recipients)
            {
                oMsg.Recipients.Add(recipient); 
            }

            if(isEncrypted)
            {
                // If caller indicates that message should be encrypted, system will add secured flag to subject
                oMsg.Subject = "<secure> " + subject;
            }
            else
            {
                // Else, message will transmit without security flag 
                oMsg.Subject = subject;
            }

            // introduces the body table
            oMsg.HTMLBody = headerConstruction.ConstructHeader(headertext,reporttitle, includedate) + bodyConstruction.ConstructBody(datatable);

            // Includes files in output message if requested
            if (includefiles)
            {
                foreach (string path in filelist)
                {
                    oMsg.Attachments.Add(path);
                }
            }

            // Send
            oMsg.Send();       
        }
joshman1019
  • 129
  • 1
  • 8
  • I'll also note that I think the "Tab"s in the body are unnecessary looking back, but in those days it helped me to keep it organized I suppose. – joshman1019 Sep 21 '20 at 22:09
  • Thanks, but unfortunately this doesn't help me because in my case I am catching attachments being added and uploading them to a server and then inserting the URL reference into the email body. – B. Leslie Sep 22 '20 at 02:55
  • That makes sense. In the alternative, you may want to try Word's find and select feature. I've used this for constructing word documents, and it can sometimes help to select the particular string and then collapse the selection. I've mentioned this in https://stackoverflow.com/questions/5628473/different-format-into-one-single-line-interop-word/23460333#23460333 In your case you would just search for the link text and then immediately collapse the selection. I think this moves the cursor to the end of the selected text. If this works, I'll repost it as a new solution. – joshman1019 Sep 22 '20 at 03:45