Email.Body not updating after editing WordEditor - c#

I have a form region for the reading pane. I retrieve the wordeditor for the forward mail item and then add info to the word document. This seems to work when I don't create and send the email in the same function, but when I want to create a forward email, edit it, and send it, the Email.Body doesn't update.
_email = this.OutlookItem as Outlook.MailItem;
private void SendForwardEmail()
{
Outlook.MailIem fEmail = null;
Word.Document doc = null;
try
{
fEmail = ((Outlook._MailItem)_email).Forward();
doc = GetWordEditor(fEmail);
EditDoc(doc);
var tmp = doc.Range().Text;
var tmp1 = fEmail.Body; // tmp1 won't have what I added to tmp
((Outlook._MailItem)fEmail).Send(); // This will send with the fEmail.Body value
// and won't show edits to the word doc
}
finally
{
Release(doc);
Release(fEmail);
}
}
I use similar code in a form region for composing emails, the difference is that by the time the Send event is triggered, the Email.Body has updated with the edits to the word doc. I've tried fEmail.Save(), but doesn't seem to work. The word editor does save the work because I can access the word editor at a different point and it will still have the edits. The Email.Body just doesn't update with the changes.
EDIT: I'll add that doing the following does update the Email.Body, but seems like a funky solution.
fEmail.Display();
((Outlook.MailItem)fEmail).Close(Outlook.OlInspectorClose.olSave);

Where and when do you run the code? Is it on a secondary thread?
Anyway, I'd suggest starting from releasing all underlying COM objects instantly. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook/Word object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. Read more about that in the Systematically Releasing Objects article.

Related

c# Outlook addin forcibly move the cursor to the end of email body

I am adding a table to the email body programmatically. I would like to move the cursor below the table after insertion. I've tried SendKeys.Send("{PGDN 10}") and have had some success but I'm not sold on the idea that this is the best way to approach it.
Are there any other ways to forcibly move the cursor down to the end of the email body?
The office model allows you to fetch the WordEditor object if you have access to the MailItem object. Once you have the WordEditor object, you can perform a Range and select to put the cursor in a specific position in the document. There might be an easier way, but this is a quick example.
var editor = oMailItem.GetInspector.WordEditor;
editor.Range(1,1).Select();
Edit
If you'd like to set the cursor to the last position in the body before the signature, you can do something like the sample below.
var originalBody = oMailItem.HTMLBody;
oMailItem.HTMLBody = newBodyHTMLStringCompiled;
var wordDocument = oMailItem.GetInspector.WordEditor;
var endingPosition = wordDocument.Content.End;
// This will append the original signature
oMailItem.HTMLBody += originalBody;
// Set the range for the cursor
wordDocument.Range(endingPosition, endingPosition).Select();

Using C# to programmatically find, and populate bookmarks in a Word 2010 Add-In

I have a Microsoft word 2010 add-in project in visual studio, I just followed the MSDN guide to making a new tab with custom functionality on the ribbon. I've done some googling, but I cant seem to find any examples (or if its even possible) to use the C# to find a bookmark, then use the bookmarks name in an SQL query and populate it. The documents I am working with can have dozens of bookmarks, and there are hundreds of documents. Automating this process is a high priority.
So basically if you want to automate word documents (building word document templates via word bookmarks) Here's how I normally go about doing it.
Copy The Template
Work On The Template
Save In Desired Format
Delete Template Copy
Each of the sections that you are replacing within your word document you have to insert a bookmark for that location (easiest way to input text in an area).
I always create a function to accomplish this, and I end up passing in the path - as well as all of the text to replace my in-document bookmarks. The function call can get long sometimes, but it works for me.
Application app = new Application();
Document doc = app.Documents.Open("sDocumentCopyPath.docx");
if (doc.Bookmarks.Exists("bookmark_1"))
{
object oBookMark = "bookmark_1";
doc.Bookmarks.get_Item(ref oBookMark).Range.Text = My Text To Replace bookmark_1;
}
if (doc.Bookmarks.Exists("bookmark_2"))
{
object oBookMark = "bookmark_2";
doc.Bookmarks.get_Item(ref oBookMark).Range.Text = My Text To Replace bookmark_2;
}
doc.ExportAsFixedFormat("myNewPdf.pdf", WdExportFormat.wdExportFormatPDF);
((_Document)doc).Close();
((_Application)app).Quit();
This code should get you up and running unless you want to pass in all the values into a function.
Sometimes if you have large amounts of fields you can build objects/classes to contain the values.
If you need more examples I'm working on a blog post as well, so I have a lot more detail if this wasn't clear enough for your use case.
You can use Spire.Doc or FreeSpire.Doc library for this purpose. I have a github repo, that I showed an example how to working it.
using Spire.Doc;
using Spire.Doc.Documents;
using Spire.Doc.Fields;
using System;
using System.Configuration;
using System.Drawing;
using System.IO;
namespace WorkingDocAndPdf
{
class Program
{
static void Main(string[] args)
{
var sourceFilePath = ConfigurationManager.AppSettings["SourceFilePath"];
var saveFilePath = ConfigurationManager.AppSettings["SaveFilePath"];
var document = new Document(sourceFilePath);
var bookmarksNavigator = new BookmarksNavigator(document);
bookmarksNavigator.MoveToBookmark("client_name");
bookmarksNavigator.ReplaceBookmarkContent("Ramil", true);
bookmarksNavigator.MoveToBookmark("client_taxno");
bookmarksNavigator.ReplaceBookmarkContent("VN-12300254178XY6", true);
bookmarksNavigator.MoveToBookmark("amount");
bookmarksNavigator.ReplaceBookmarkContent("871 AZN", true);
bookmarksNavigator.MoveToBookmark("date");
bookmarksNavigator.ReplaceBookmarkContent(DateTime.Now.ToString("dd.MM.yyyy"), true);
//It is for picture
var sealPath = ConfigurationManager.AppSettings["SealPath"];
bookmarksNavigator.MoveToBookmark("seal", true, true);
var section = document.AddSection();
var image = Image.FromFile(sealPath);
var paragraph = section.AddParagraph();
paragraph.AppendPicture(image);
bookmarksNavigator.InsertParagraph(paragraph);
document.Sections.Remove(section);
if (!Directory.Exists(saveFilePath))
Directory.CreateDirectory(saveFilePath);
var saveFileFullPath = $"{saveFilePath}\\{Guid.NewGuid()}.pdf";
//It is for refresh cross reference bookmark, that you can use one bookmark on different location in document. In word shortcut it is `CTRL A + F9`
document.IsUpdateFields = true;
document.SaveToFile(saveFileFullPath, FileFormat.PDF);
}
}
}
For more information, you can visit my github repo: WorkingDocAndPdf_FreeSpireDoc
My article about FreeSpire.Doc (but written in Azerbaijani): C# working Word and PDF files. Print forms

Creating and adding Outlook Signature

I've created a html template with a couple of replacement variables.
Adding the created signature-template as signature for reply and new messages does not seem to get outlook to default to it.
//string signatureName = "Example.htm";
//Set via office-interop new signature as default
//using Microsoft.Office.Interop.Word;
Application app = new Application();
var opt = app.EmailOptions.EmailSignature;
opt.NewMessageSignature = signatureName;
opt.ReplyMessageSignature = signatureName;
app.Quit(); //Also tried WdSaveOptions.wdSaveChanges
Marshal.ReleaseComObject(app);
Outlook displays the added signature (TEST_...) but does not recognize it as default signature. Instead it just removed the previous default signature and now has none.
Is there something else required to tell outlook to set it as default ?
The Outlook object model doesn't provide anything for that. Of course, as a workaround you may use the Word object model for setting signatures as you did in the code above:
Application app = new Application();
var opt = app.EmailOptions.EmailSignature;
opt.NewMessageSignature = "Eugene Astafiev";
opt.ReplyMessageSignature = "E.Astafiev";
app.Quit(); //Also tried WdSaveOptions.wdSaveChanges
Marshal.ReleaseComObject(app);
But you need to assign a real HTML markup or text which represents the signature, not an HTML document filename.
Anyway, all settings are stored in the windows registry. See Set Default Signature outlook for more information.
Apparently the problem was something... quite simple.
string signatureName = "Example.htm";
Outlook/Word expects the signature-name without the file-extension. Passing "Example" instead of "Example.htm" worked.

Copying mail body to new mail in outlook by coding in c#

In Outlook 2013, I want the content of the mail body in a new mail programmatically.
Below is my code:
void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
Outlook.MailItem mailItem = Inspector.CurrentItem as Outlook.MailItem;
Outlook.Application oApp = new Outlook.Application();
Outlook.Explorer oExplorer = oApp.ActiveExplorer();
Outlook.Selection oSelection = oExplorer.Selection;
foreach (object item in oSelection)
{
Outlook.MailItem mi = (Outlook.MailItem)item;
mailItem.HTMLBody = mi.HTMLBody;
}
}
Everything works fine, but the image present in the original mail is not displayed. Instead it shows something like cid:image002.png.
Not sure what is the reason.
Also I want to give it to the client, so I can't save mail content locally.
If you see cid:image002.png statements in the HTML markup of the message body you need to attach embedded items to new emails as well.
The basic principle of adding an embedded image is to attach the image to the item and then using the HTMLBody to write HTML to add the attachment cid as a reference in the HTML.
Attachment attachment = newMail.Attachments.Add(
#"E:\Pictures\image001.jpg"
, OlAttachmentType.olEmbeddeditem
, null
, "Some image display name"
);
string imageCid = "image001.jpg#123";
attachment.PropertyAccessor.SetProperty(
"http://schemas.microsoft.com/mapi/proptag/0x3712001E"
, imageCid
);
newMail.HTMLBody = String.Format(
"<body><img src=\"cid:{0}\"></body>"
, imageCid
);
Be aware, you will need to save the file on disk and the re-attach it to the new email. The Add method of the Attachment class accepts a file (represented by the full file system path with a file name) or an Outlook item that constitutes the attachment.
Also I'd recommend avoiding the foreach loop in the code with OOM objects. Use the for loop instead. It allows to release underlying COM objects instantly. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. You can read more about that in the Systematically Releasing Objects article.
As i understand you want to copy the attachments from existing mailitem to new one... Then you can try this
foreach( var x in mailItem.Attachments)
{
mi.Attachments.Add(x);
}

Creating an rtf custom mail item

I'm using redemption to create a custom mail item and save it in the draft folder of my outlook. Currently the mailItem is saved in HTML format. I want to be able to save it in rtf Format. How can I do that ?
Here is the code I am using :
Redemption.RDOSession session = new Redemption.RDOSession();
session.MAPIOBJECT = olApp.Session.MAPIOBJECT;
Redemption.RDOFolder rFolder = session.GetDefaultFolder(Redemption.rdoDefaultFolders.olFolderDrafts);
Redemption.RDOMail rMsg = rFolder.Items.Add("ipm.note.mep");
// modify some custom fields ...
rMsg.BodyFormat = 3;
rMsg.Save();
Outlook.MailItem oMep = olApp.Session.GetItemFromID(rMsg.EntryID);
oMep.BodyFormat = Outlook.OlBodyFormat.olFormatRichText;
oMep.Display(false);
Changing the bodyFormat doesn't seem to work. I also tried the saveAs method with no success. I can change the format manually when the mailItem is open, but I want to do that automatically within my C# code.
Have you tried to set the RDOMail.RtfBody property?

Categories

Resources