Outlook VSTO - mailItem body problems - c#

I'm having a problem with email sending in C#.
I'm working on an add-in and everything is going well. I can send my mails, like i want, but not "two times in a row".
For example, my add-in open a Form and after the user action an email is sent.
When the mail is sent, the form is closed and that's okay.
But some time, i need to send two separate emails and the body of second email is always empty. By the way, i fill the "body" of my mails with Word (Microsoft.Office.Interop.Word) to have some formatted text.
If I use the .Body property there is no problem.
Now, I'm wondering if it's not the fault of "Word" because the email part is working but only the body is empty.
I tried to send my mails in the inverse order to see if it's occurs always with the second mail and i was right. It's not about the email or his content but more about being the second sent.
It may be some things which haven't been released yet(not properly released objects) or something like that but i'm doing already it.
That's how i'm doing..
Outlook.MailItem mailItem = (Outlook.MailItem)new Outlook.Application().CreateItem(Outlook.OlItemType.olMailItem);
try
{
mailItem.CC = currentUserExchange.PrimarySmtpAddress;
mailItem.Importance = Outlook.OlImportance.olImportanceHigh;
mailItem.Subject = "XXX";
mailItem.To = finalRecipients;
fillBody(mailItem, mailBody);
mailItem.Send();
}
catch (Exception ex) { }
finally
{
releaseObject(mailItem);
}
if (moderatorPin != String.Empty)
{
Outlook.MailItem mailItemSecurity = (Outlook.MailItem)new Outlook.Application().CreateItem(Outlook.OlItemType.olMailItem);
try
{
mailItemSecurity.Importance = Outlook.OlImportance.olImportanceHigh;
mailItemSecurity.Subject = "XXX";
mailItemSecurity.To = currentUserExchange.PrimarySmtpAddress;
fillBody(mailItemSecurity, mailBodySecure);
mailItemSecurity.Send();
}
catch (Exception ex) { MessageBox.Show("error : " + ex.Message); }
finally
{
releaseObject(mailItemSecurity);
}
}
and :
private void fillBody(Outlook.MailItem mailItem, String bodyMail)
{
Word.Document document = mailItem.GetInspector.WordEditor;
Word.Range rng = document.Paragraphs[1].Range;
try
{
document.Paragraphs[1].LineSpacingRule = Word.WdLineSpacing.wdLineSpaceSingle;
rng.set_Style(Word.WdBuiltinStyle.wdStyleHtmlKbd);
rng.Font.Color = (Word.WdColor)(fontColor.R + 0x100 * fontColor.G + 0x10000 * fontColor.B);
rng.Text = bodyMail;
rng.Select();
}
catch (Exception ex)
{
MessageBox.Show("XXX");
}
finally
{
releaseObject(rng);
releaseObject(document);
}
}

Related

c# vsto Outlook.ApplicationEvents_11_NewMailEx

Using Visual Studio 2022
outlook 365 with IMAP account
VSTO addin.
c#
Event : newmaileX to capture every incoming email. If certain subject, then I enter text into the body. If body is html, I find the tag and insert after. I have create a button on ribbon to test, and the email subject is altered and new text is in the body.
fine so far.
When the newmailex is fired, it runs my code, but sometimes it does not save the changes, and sometimes it does.
Why ?
if I add "mailItem.Save()" this works, but I then get duplicates of the same email. Sometimes upto 10 duplicates. Is this an IMAP thing ? Below is my code.
void NewMail_Event(String entryIDCollection)
{
Outlook.NameSpace outlookNS = this.Application.GetNamespace("MAPI");
Outlook.MailItem mailItem = null;
try
{
string sTag;
string sBody;
int nPos;
sTag = "<table border=\"1\" cellspacing=\"0\"><tr bgcolor=\"#f5e942\"><td><font color=\"#FF0000\" size=\"4\">";
sTag += "This email originated from outside and was not listed in our safe senders list.<br>";
sTag += "DO NOT action, click on any links or open attachments unless you recognise the sender and know the content is safe.";
sTag += "</font></td></tr></table><br>";
string sSubject = null;
string filter = "[EXTERNAL]";
string[] sEmails = entryIDCollection.Split(',');
foreach (string sEmail in sEmails)
{
mailItem = (Outlook.MailItem)outlookNS.GetItemFromID(sEmail, Type.Missing);
if (mailItem.Subject != null)
{
File.AppendAllText("c:\\1data\\desktop\\vstolog.txt", mailItem.Subject + "\r\n");
if (mailItem.Subject.Length >= 10)
{
if (mailItem.Subject.ToUpper().StartsWith(filter))
{
sSubject = mailItem.Subject.Substring(filter.Length, mailItem.Subject.Length - filter.Length);
mailItem.Subject = sSubject;
sBody = mailItem.HTMLBody;
if (sBody.Contains("<body>") || sBody.Contains("<BODY>"))
{
if (sBody.Contains("<BODY>"))
{
sBody = sBody.Replace("<BODY>", "<body>" + sTag);
}
else
{
sBody = sBody.Replace("<body>", "<body>" + sTag);
}
}
else
{
if (sBody.Contains("<body") || sBody.Contains("<BODY"))
{
if (sBody.Contains("<body"))
{
nPos = sBody.IndexOf("<body", 0);
}
else
{
nPos = sBody.IndexOf("<BODY", 0);
}
nPos = sBody.IndexOf(">", nPos);
sBody = sBody.Insert(nPos + 1, sTag);
}
else
{
sBody = sTag + sBody;
}
}
if (mailItem.BodyFormat == OlBodyFormat.olFormatHTML)
{
mailItem.HTMLBody = sBody;
}
else
{
mailItem.Body = sBody;
}
//mailItem.Close(OlInspectorClose.olSave);
}
}
}
Marshal.ReleaseComObject(mailItem);
mailItem = null;
}
}
catch (Exception eX)
{
MessageBox.Show(eX.Message);
}
finally
{
if (mailItem != null) Marshal.ReleaseComObject(mailItem);
mailItem = null;
if (outlookNS != null) Marshal.ReleaseComObject(outlookNS);
outlookNS = null;
}
}
You can find similar issues described in case of IMAP profiles configured in Outlook, see IMAP Sent Messages are duplicated and unread in Sent Items folder for more information.
I suppose you are handling the NewMailEx event of the Application class, not the NewMail one. There are several aspects in the code:
string[] sEmails = entryIDCollection.Split(',');
The EntryIDsCollection string contains the Entry ID that corresponds to that item. Note that this behavior has changed from earlier versions of the event when the EntryIDCollection contained a list of comma-delimited Entry IDs of all the items received in the Inbox since the last time the event was fired.
However, depending on the setup on the client computer, after a new message arrives in the Inbox, processes like spam filtering and client rules that move the new message from the Inbox to another folder can occur asynchronously. You should not assume that after these events fire, you'll always get a one-item increase in the number of items in the Inbox.
As a possible workaround you may try to handle the ItemAdd event on the target folder instead.

How do I send a mail from , from MailID in outlook (programmatically configured from mailid) using asp.net c#

using Outlook = Microsoft.Office.Interop.Outlook;
I'm able to sending the mail using above Outlook dll but I want to send a mail which I configured in the the logic "FROM' MailID only
I'm trying to sending the mail which I configured mail only "FROM", but while I'm sending the mail I'm getting error
Outlook does not recognize one or more names
where did I make the mistake and how to send the logically written FROM MailID only?
public int sendMFSwitchMail(MAEEmail mAEEmail , string data)
{
try
{
// Create the Outlook application.
Outlook.Application oApp = new Outlook.Application();
// Create a new mail item.
Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
//string pathfilecontent = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + #"\payment_failed_mail.html";
string pathfilecontent = Server.MapPath(#"\payment_failed_mail.html");
string contentmailstr = "";
//if (string.IsNullOrEmpty(mAEEmail.Body))
// contentmailstr = File.ReadAllText(pathfilecontent);
//else
// contentmailstr = mAEEmail.Body;
contentmailstr = File.ReadAllText(pathfilecontent);
contentmailstr = contentmailstr.Replace("Full_Name", data);
//contentmailstr = contentmailstr.Replace("Existing_Baskets_Constituents", oldfund);
//contentmailstr = contentmailstr.Replace("New_Baskets_Constituents", newfund);
oMsg.HTMLBody = contentmailstr;// sb.ToString();
//oMsg.HTMLBody = mAEEmail.Body;
//Subject line
oMsg.Subject = mAEEmail.Subject;
//if (!string.IsNullOrEmpty(mAEEmail.BCC))
// oMsg.BCC = mAEEmail.BCC;
Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients;
// {"Outlook does not recognize one or more names. "}
oRecips.Add(mAEEmail.From);//from mail:abc#cyient.com[outlook, programmatically configured mailid]
oRecips.Add(mAEEmail.Password);
//Change the recipient in the next line if necessary.
Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add(mAEEmail.To); // to mail : a#gmail.com
oRecip.Resolve();
// Send.
//Console.WriteLine("Sending email...");
oMsg.Send();
// Clean up.
oRecip = null;
oRecips = null;
oMsg = null;
oApp = null;
//return 1;
}
catch(Exception ex)
{
//MessageBox.Show("Error is :" + ex.Message.ToString());
//throw;
Response.Write("Error is :" + ex.Message.ToString());
//loggingService.Log("Error is:" + ex.Message.ToString());
}
return 1;
}
You are adding the sender as one of the recipients, that does not make much sense. The error you are getting means the name cannot be resolved, which means it is not an SMTP address or a name in your contacts. Are you sure you the value if just an SMTP address?
To specify the sender, you need to either set the MailItem.SendUsingAccount property to one of the Account objects from the Application.Session.Accounts collection, or, in case of Exchange, set the MailItem.SentOnBehalfOfName property to the name (not address) of another Exchange user on whose behalf you are allowed to send.

outlook download email body

I am creating a program that sends a text message and then depending on the reply I want to perform a specific action. Anyways here is my code:
using Microsoft.Office.Interop.Outlook;
using Outlook = Microsoft.Office.Interop.Outlook;
static void Main()
{
var outlook = new Microsoft.Office.Interop.Outlook.Application();
// fire event when a new email arives
outlook.NewMailEx += new ApplicationEvents_11_NewMailExEventHandler(oApp_NewMailEx);
// etc
}
static void oApp_NewMailEx(string EntryIDCollection)
{
var outlook = new Microsoft.Office.Interop.Outlook.Application();
MailItem temp = (MailItem)outlook.Session.GetItemFromID(EntryIDCollection, Missing.Value);
var body = temp.Body; // the body of the email is null! I tried waiting and it is null until I open it...
Console.WriteLine(body);
}
This part is not important but I send the "text message" with this function:
// send text message "att.txt.net only works with at&t phones"
public static int SendEmail(string recipeint = "9546543930#att.txt.net")
{
try
{
// Create the Outlook application by using inline initialization.
Outlook.Application oApp = new Outlook.Application();
//Create the new message by using the simplest approach.
Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
Outlook.Accounts accounts = oMsg.Session.Accounts;
foreach (Outlook.Account account in accounts)
{
// When the e-mail address matches, send the mail.
if ( account.SmtpAddress.Contains("gmail") )
{
oMsg.SendUsingAccount = account;
break;
}
}
// If you want to, display the message.
oMsg.Display(true); //modal
//Add a recipient.
Outlook.Recipient oRecip = (Outlook.Recipient)oMsg.Recipients.Add(recipeint);
oRecip.Resolve();
//Set the basic properties.
oMsg.Subject = "This is the subject of the test message";
oMsg.Body = "This is the text in the message.";
//Add an attachment.
// TODO: change file path where appropriate
//String sSource = "C:\\setupxlg.txt";
//String sDisplayName = "MyFirstAttachment";
//int iPosition = (int)oMsg.Body.Length + 1;
//int iAttachType = (int)Outlook.OlAttachmentType.olByValue;
//Outlook.Attachment oAttach = oMsg.Attachments.Add(sSource, iAttachType, iPosition, sDisplayName);
//Send the message.
oMsg.Save();
oMsg.Send();
//Explicitly release objects.
oRecip = null;
//oAttach = null;
oMsg = null;
oApp = null;
}
// Simple error handler.
catch (System.Exception e)
{
Console.WriteLine("{0} Exception caught: ", e);
}
//Default return value.
return 0;
}
So I am able to send an email with my gmail account and when I reply to the text message the function oApp_NewMailEx gets executed with the id of the new email. I am able to get the subject but the body does not get downloaded until I hover my mouse over the email or open the email. I already waitied 2 minutes on another thread and then tried to see the body and it was still null.
Edit note to make this work I have:
It looks gray out because I did not run outlook as an administrator. If You run outlook as an admin you will be able to update the security settings.
I also imported the Microsoft Outlook 14.0 Object library as a reference.
Once I received the email I called the send and receive method. wait a little and then I was able to read the body.
outlook.Session.SendAndReceive(false);

Outlook returns error: The messaging interface has returned an unknown error

I am having some problems with a piece of code, I am trying to import data from a source (at this time an access database) into a custom form but i keep getting the above error.
When i use a VBscript inside the source database all contacts import correctly.
When i repair the PST it still gives this error.
When i add a delay of 450 ms. the error also occurs but later on in the process.
Having Outlook opened or closed does not matter.
I am using the following method
string[] arrFolders = strFolders.Split('\\');
Outlook.Application app = null;
Outlook.MAPIFolder folder = null;
try {
app = new Outlook.Application();
folder = app.GetNamespace("MAPI").Folders[arrFolders[0]];
} catch (Exception ex) {
writeLogLine("Error creating Outlook instance: " + ex.Message);
MessageBox.Show("Error creating Outlook instance\r\n" + ex.Message);
intErrorCount++;
blnHasErrors = true;
blnAbort = true;
}
try {
for (int i = 1; i < arrFolders.Length; i++) {
folder = folder.Folders[arrFolders[i]];
}
} catch (Exception ex) {
writeLogLine("Error navigating to DRM folder: " + ex.Message);
MessageBox.Show("Error navigating to DRM folder\r\n" + ex.Message);
intErrorCount++;
blnHasErrors = true;
blnAbort = true;
}
setProgressbarMaximum(dtResults.Rows.Count);
setProgressbarMode(ProgressBarStyle.Continuous);
//int intRowCount = 0;
foreach (DataRow drItem in dtResults.Rows) {
if (strDRMType == "Contact") {
try {
Outlook.ContactItem x = (Outlook.ContactItem)folder.Items.Add("IPM.Contact." + strFormName);
for (int i = 0; i < arrMappings.GetLength(0); i++) {
if (arrMappings[i, 1] != null && drItem[arrMappings[i, 0]].ToString() != "") {
x.UserProperties[arrMappings[i, 1]].Value = drItem[arrMappings[i, 0]].ToString();
}
}
x.Save();
} catch (Exception ex) {
writeLogLine("Error importing contact: " + ex.Message);
intErrorCount++;
blnHasErrors = true;
}
}
as i said, when i loop the code it will throw exceptions after 100 to 200 contacts, when i add a delay it will get to contact 400/500 before failing.
This code is supposed to be for a generic import tool for this specific form so there is no need for hardcoding the source column names to the form fields in the import code.
Any help is appreciated.
I'm assuming this is not an Outlook add-in, since you say it doesn't matter if OL is open or closed, right?
One thing you may want to do is ensure you are releasing the COM objects once you are done with them, using System.Runtime.InteropServices.Marshal.ReleaseComObject(...). Also, when you use dot notation like "namespace.Folders[..].Name" you are actually leaking a reference to both the Folders collection object and a Folder object.
When you do folders.Items.Add(...) inside a loop, that leaks a lot of objects.
So, clean up your COM references first, and see how that affects your situation.
Here's how I typically use COM objects:
MyComLib.Foo foo = null;
try
{
foo = new MyComLib.Foo();
foo.DoSomething();
} catch(COMException exc)
{
// handle error, or rethrow
}
finally
{
if(foo != null)
Marshal.ReleaseComObject(foo);
}

C# Sending Email - Sanity check

Sanity check of an email implementation please :-) Anything obvious I've missed?
string supplierOfThisMaterialEmailAddress = "davexxx#gmail.com"; // TODO
string htmlBodyIncludingReplacements = "<html><head><title>E-mail</title></head><body><div>. There has been a request on the hello.co.nz website for: " + txtMaterialDescription.Text +
"<br />Full Name: <b>" + fullName + "</b><br />" +
etc..";
string textOnlyBodyIncludingReplacements = "E-mail. There has been a request on the freematerials.co.nz website for: " + txtMaterialDescription.Text +
"Full Name: " + fullName +
"etc..";
string subject = "Someone has contacted you";
CustomMailer mailer = new CustomMailer();
string result = mailer.SendEmail(subject, htmlBodyIncludingReplacements, supplierOfThisMaterialEmailAddress, textOnlyBodyIncludingReplacements);
if (result != null)
lblMessage.Text = result;
else
lblMessage.Text = "Thank you - email has been sent";
And the class:
public class CustomMailer
{
public string SendEmail(string subject, string htmlBodyIncludingReplacements, string emailTo, string textOnlyBodyIncludingReplacements)
{
try
{
MailAddress sender = new MailAddress("dave#hello.co.nz", "Dave Mateer");
emailTo = "dave#hello.co.nz"; // testing
MailAddress recipient = new MailAddress(emailTo, null);
MailMessage message = new MailMessage(sender, recipient);
message.Subject = subject;
AlternateView textView = AlternateView.CreateAlternateViewFromString(textOnlyBodyIncludingReplacements, null, "text/plain");
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(htmlBodyIncludingReplacements, null, MediaTypeNames.Text.Html);
message.AlternateViews.Add(textView);
message.AlternateViews.Add(htmlView);
SmtpClient client = new SmtpClient();
client.Send(message);
}
catch (Exception ex)
{
throw new Exception();
}
return null;
}
}
At first glance, catching a general Exception object and throwing a new one is going to have the net effect of eating any exceptions thrown by SendEmail.
The rest looks okay.
You should change the
catch (Exception ex)
{
throw new Exception();
}
to :
catch (Exception ex)
{
throw;
}
because otherwise you lose all the data that came with the original excepion that was thrown

Categories

Resources