Parse Outlook email in Inbox which belongs to other account - c#

I am trying to create a service which will run as a background service on a server. This service will parse email as soon as it enters the Inbox.
We have one email account abc#organization.com. We are using Outlook to check the emails. It is a service so Outlook won't be running all the time on the server. I want to parse the email automatically for this account. This account is not my email account. I am using Microsoft.Office.Interop.outlook in C# program.
This program is running but it is parsing email from my email inbox. I don't know how to specify specific email to parse the Inbox. Need to know the event which triggers as soon as new mail arrives. My program parsed half the emails from my inbox but after that it is throwing object null reference error.
static void Main(string[] args)
{
Microsoft.Office.Interop.Outlook.Application myApp=new Microsoft.Office.Interop.Outlook.Application();
try
{
String Subject, Body, Createdate, Sender = null;
Microsoft.Office.Interop.Outlook.NameSpace mapinamespace = myApp.GetNamespace("MAPI");
mapinamespace.Logon(null, null,true,true);
Microsoft.Office.Interop.Outlook.MAPIFolder myInbox = mapinamespace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
Microsoft.Office.Interop.Outlook.Accounts accounts = myApp.Session.Accounts;
try
{
foreach (Microsoft.Office.Interop.Outlook.Account account in accounts)
{
if (account.SmtpAddress == "abc#organization.com")
{
Console.Write(account);
}
else
{
Console.Write("Not found ---");
}
}
}
catch{
throw new System.Exception(string.Format("No account with amtp:{0} exists!"));}
foreach (object item in myInbox.Items)
{
try
{
var mail = item as MailItem;
if (mail != null)
{
//Creation date
Createdate = mail.CreationTime.ToString();
Console.WriteLine("CreationTime---" + Createdate);
//Grab the senders address
Sender = mail.SenderEmailAddress.ToString();
Console.WriteLine("Sender's E-mail---" + Sender);
//grab the Subject
Subject = mail.Subject.ToString();
Console.WriteLine("Subject--" + Subject);
//Grab the body
Body = mail.Body.ToString();
Console.WriteLine("Body---" + Body);
//Grab the Attachment
}
else
{
Console.Write("Error in mail---");
}
}
catch (System.Runtime.InteropServices.COMException e)
{
Console.Write(e);
}
}
}
catch (System.Runtime.InteropServices.COMException e)
{
Console.Write(e);
}
}

I am trying to create a service which will run as a background service on server.
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution.
You can read more about that in the Considerations for server-side Automation of Office article.
Anyway, it looks like you are interested in the NewMailEx event of the Application class. Also I'd suggest reading the following series of articles:
Outlook NewMail event unleashed: the challenge (NewMail, NewMailEx, ItemAdd)
Outlook NewMail event: solution options
Outlook NewMail event and Extended MAPI: C# example
Outlook NewMail unleashed: writing a working solution (C# example)

Related

Is there a way to handle/turn off dialogs from Outlook while sending emails with encryption in place (with C# WPF)?

I have a C# WPF application, one of its functionalities it to send series of emails through local Outlook/account. It utilizes Microsoft.Office.Interop.Outlook COM. The thing is that I need to encrypt emails. I'm handling it with following approach:
using Outlook = Microsoft.Office.Interop.Outlook;
(...)
Outlook.Application olkApp = new Outlook.Application();
Outlook.MailItem otlMail = olkApp.CreateItemFromTemplate(templateFullPath) as Outlook.MailItem;
otlMail.To = (...)
try
{
const string PR_SECURITY_FLAGS = http://schemas.microsoft.com/mapi/proptag/0x6E010003";
long prop = Convert.ToInt64(otlMail.PropertyAccessor.GetProperty(PR_SECURITY_FLAGS));
var ulFlags = 0x0;
ulFlags = (ulFlags | 0x1); // SECFLAG_ENCRYPTED
//ulFlags = (ulFlags | 0x2); // SECFLAG_SIGNED
otlMail.PropertyAccessor.SetProperty(PR_SECURITY_FLAGS, ulFlags);
}
catch (Exception ex)
(...)
try
{
otlMail.Send();
}
catch (Exception ex)
{
(...)
}
Since I send these emails over to company's accounts, in theory all employees should have valid certificates (PKI card). In practice some folks for sure will not comply that requirement (for some reasons). So, when I'm testing the app, simulating such problem, the Outlook displays a dialog asking for decision:
Microsoft Outlook had problems encrypting this message because the following recipients had missing or invalid certificates, or conflicting or unsupported encryption capabilities: (some email address).
Continue will encrypt and send the message but listed recipients may not be able to read it.
[Send Unencrypted] [Continue] [Cancel]
The application is waiting endlessly for user decision. I find it inconvenient for user.
In case such a problem occurs I'd see either:
disable such dialogs and ensure the exception would be thrown so that I can trace problematic accounts, or...
handle such dialogs in an automated manner somehow.
Registry changes are not an option.
Can anybody help please?
Regards,
Kris
The Outlook object model doesn't provide anything for suppressing such dialogs automatically.

Opening multiple Outlook Window Send Email with C#

I need to open several Outlook windows previously populated with ticulo and email body for later user to inform the senders. I need to open several windows (I walk a grid to know how many windows).
I'm trying to do this with threads but an error message occurs saying: Outlook can not do this because the dialog box is open. Please close it and try again "
How to open multiple competing windows?
Test Call
private void button2_Click(object sender, EventArgs e)
{
int qtdEventos = dgvDescEvento.RowCount;
Thread[] Threads = new Thread[qtdEventos];
try
{
cEmail testeEmail = new cEmail();
for (int i = 0; i < qtdEventos; i++)
{
Threads[i] = new Thread(new ThreadStart(new cEmail().Monta));
}
foreach (Thread t in Threads)
{
t.Start();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace NavEventos.Class
{
class cEmail
{
private Outlook.Application outlookApp;
public cEmail()
{
outlookApp = new Outlook.Application();
}
public void Monta()
{
string pTitulo = "Title";
string pAssunto = "Body test";
Outlook._MailItem oMailItem = (Outlook._MailItem)outlookApp.CreateItem(Outlook.OlItemType.olMailItem);
Outlook.Inspector oInspector = oMailItem.GetInspector;
Outlook.Recipients oRecips = (Outlook.Recipients)oMailItem.Recipients;
#region MONTA ASSUNTO
oMailItem.Subject = pTitulo;
#endregion
#region MONTA CORPO DO E-MAIL
oMailItem.Body = pAssunto;
#endregion
oMailItem.Display(true);
}
}
}
You may not like this... but you shouldn't try. ;(
As you can see the Outlook COM interface is trying very hard to prevent you from doing this, it is one of the limitations of the outlook automation libraries that displaying a mail item is done in a modal kind of way.
There is good reason for this, your user is in your LOB application, then your code wants them to read an email in outlook, which you have done using the COM automation libraries for outlook. Now their outlook icon in the toolbar is flashing because a new email modal window has opened up, but this dialog may have opened up behind your current LOB app.
Now the user will need to switch context into Outlook to see the dialog and read the email.
If you can review your need to open these emails all at the same time then you and outlook com automation will get along just fine :)
Otherwise consider writing a plugin for Outlook and moving your email management routines into outlook itself. In there you can be very creative, sounds like you really need just a master - detail style of interface, like the main outlook browser, so you have a list of these emails and as the user clicks on them they are displayed in the preview inspector.
Maybe the solution is to use your logic to move these messages into a
specific folder in outlook, then use Outlook automation to make this
folder the current active window in outlook, then the user can decide
which emails they want to action or not.

How to read from functional mailbox in ASP.NET with application on server

I'm developing an application that will have about 15 users. Each user will have to programmatically be able to click a button and read the emails in their shared functional mailbox (which is called Media processing).
When I test my code locally, everything works fine. But now that I published it to the server, it's not working anymore (because it's probably looking in the mailbox on the server instead of on the users' mailbox.
In my web.config:
<add key="asFuncMailboxInbox" value="Media Processing" />
<add key="asFuncMailboxOutbox" value="902. Outbox" />
This is my method to process the emails:
string inboxName = WebConfigurationManager.AppSettings["asFuncMailboxInbox"];
string outboxName = WebConfigurationManager.AppSettings["asFuncMailboxOutbox"];
try
{
OutlookApp myApp = new OutlookApp();
OutlookNameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
MapiFolder myInbox = mapiNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
MapiFolder mySubFolder = myInbox.Folders[inboxName];
MapiFolder destinationFolder = myInbox.Folders[outboxName];
var myItems = mySubFolder.Items;
myItems.Sort("[ReceivedTime]", true);
count = 0;
if (myItems.Count > 0)
{
totalCount = myItems.Count;
for (var i = myItems.Count; i > 0; i--)
{
var itemObject = myItems[i] as MailItem;
if (itemObject != null)
{
var isOk = NewBankFactoryHelper.IsMessageCorrectlyConstructed(itemObject.Body);
if (isOk)
{
StoreNewBankRequestEmailData(itemObject);
itemObject.Move(destinationFolder);
count++;
}
}
}
}
}
catch (System.Exception e)
{
hasError = true;
errorMessage = e.ToString();
}
finally
{
template = string.Format(CommonResources.Label_RequestsDownloadSuccess, count, totalCount);
if (count < totalCount)
{
template += CommonResources.Label_EmailIncorrectFormat;
}
if (hasError)
{
template += string.Format(CommonResources.Label_RequestDownloadFailed, errorMessage);
}
}
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution. Read more about that in the Considerations for server-side Automation of Office article.
If you deal with Exchange mailboxes only you may consider using EWS, see EWS Managed API, EWS, and web services in Exchange for more information. Also you may consider using any third-party components which don't require Outlook installed on the machine. Or just use a low-level API - Extended MAPI.

Issues reading unread mails in Outlook

I am trying to develop an add-in for Outlook. In that I want remove attachment when a new mail is received.
So I call my function on the NewMailEx event. It is working fine. In that function I try to find unread mails in the Outlook inbox. From those I remove the attachments.
My problem is: when I open Outlook, the first mail I received is not showing in the inbox (not in outlook c# code), so I can't remove the attachment from that mail.
From the second mail (after the first mail), I can get the received mail, so I can remove the attachments.
Whenever I close and reopen Outlook, the first mail I receive gives this problem.
At the first mail received there is no unread mail.
private void Application_NewMailEx(object Item)
{
string senderEmailid = string.Empty;
outlookNameSpace = this.Application.GetNamespace("MAPI");
Outlook.Application myApp = new Outlook.Application();
Outlook.NameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
Outlook.MAPIFolder myInbox = mapiNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
Outlook.Attachments attachments;
int test = myInbox.Items.Count;
Microsoft.Office.Interop.Outlook.Recipients recipients = ((Outlook.MailItem)myInbox.Items[test]).Recipients;
Outlook.Items unreadItems = myInbox.Items.Restrict("[Unread]=true");
if (unreadItems.Count > 0)
{
foreach (Outlook.MailItem mail in unreadItems)
{
Outlook.Recipient recip;
Outlook.ExchangeUser exUser;
string sAddress;
if (mail.SenderEmailType.ToLower() == "ex")
{
recip = Globals.ThisAddIn.Application.GetNamespace("MAPI").CreateRecipient(mail.SenderEmailAddress);
exUser = recip.AddressEntry.GetExchangeUser();
sAddress = exUser.PrimarySmtpAddress;
}
else
{
sAddress = mail.SenderEmailAddress.Replace("'", "");
}
string[] emailAddressPart = sAddress.Split('#');
string strSenderDomain = emailAddressPart[1];
if (lstDomain.Any(item => item.Contains(strSenderDomain)))
{
attachments = mail.Attachments;
int nAttachmentCount = mail.Attachments.Count;
if (nAttachmentCount > 0)
{
int j = nAttachmentCount;
for (int i = 1; i <= nAttachmentCount; i++)
{
mail.Attachments[j].Delete();
j--;
}
}
}
}
}
}
The NewMailEx event of the Application class is not the best place for searching unread emails. This event fires once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem. The EntryIDsCollection string contains the Entry ID that corresponds to that item. The alternative way is to handle the ItemAdd event of the Items class.
Instead, you can wait until Outlook finishes synchronizing items and run your code for searching unread emails. The SyncEnd event of the SyncObject class is fired immediately after Microsoft Outlook finishes synchronizing a user’s folders using the specified Send/Receive group.
Also you may consider handling the Startup or MAPILogonComplete events. But they are fired before the synchronization is completed. Consider using a timer to run the procedure a bit after Outlook is started.
You can read about possible ways of handling incoming emails in the following series of articles:
Outlook NewMail event unleashed: the challenge (NewMail, NewMailEx, ItemAdd)
Outlook NewMail event: solution options
Outlook NewMail event and Extended MAPI: C# example
Outlook NewMail unleashed: writing a working solution (C# example)
Also I'd recommend breaking the chain of calls and delaclaring each property or method call on a separate line of code. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. This is particularly important if your add-in attempts to enumerate more than 256 Outlook items in a collection that is stored on a Microsoft Exchange Server. If you do not release these objects in a timely manner, you can reach the limit imposed by Exchange on the maximum number of items opened at any one time. 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 in MSDN.
There is nothing you can do about that. From the documentation on NewMailEx:
Also, the event will fire only if Outlook is running. In other words, it will not fire for the new items that are received in the Inbox when Outlook was not open.
That means you have to manually call your method to walk down all the unread emails when opening Outlook.

How to Program Outlook 2007 Add-In with Multiple Mailboxes

I'm trying to figure how to write a simple add-in for Excel 2007, but one that only interacts with one of my mailboxes. Currently I have two email addresses coming into my outlook, each in a specific 'mailbox'. I was wondering, how would I specify a NewMail event for a specific mailbox?
Or, perhaps not as clean, but how could I write an if function that specifies which mailbox / email any new item is addressed to...
Hopefully this makes sense. Thanks
To catch new mail event, add this code to addin startup method:
this.Application.NewMailEx +=
new Outlook.ApplicationEvents_11_NewMailExEventHandler(Application_NewMailEx);
Then add method to handle NewMailEx event:
void Application_NewMailEx(string EntryID)
{
// get MailItem for this new mail
Outlook.Explorers explorers = this.Application.Explorers;
Outlook.MailItem newMail =
(Outlook.MailItem)explorers.Application.Session.GetItemFromID(EntryID, System.Reflection.Missing.Value);
// check SendUsingAccount to see if it came in mailbox we are interested in
if (newMail.SendUsingAccount.DisplayName == "your.name#your.domain.com")
{
// do whatever You like
}
}
Add using statement also:
using Outlook = Microsoft.Office.Interop.Outlook;

Categories