Getting multiple address for a mail in .pst files - c#

I have successfully read the .pst files thorough C#.
The issue is if a mail has multiple recipient (i.e. sender email address) then I am not able to get those multiple address. with the code
Outlook.Application app = new Outlook.Application();
Outlook.NameSpace outlookNs = app.GetNamespace("MAPI");
outlookNs.AddStore(#"D:\pst\Test.pst");
Outlook.MAPIFolder emailFolder = outlookNs.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderSentMail);
List<MailItem> lstMails = emailFolder.Items.OfType<MailItem>().Where(x=>x.SenderEmailAddress.Contains("hari")).Select(x=>x).ToList();
foreach (Object obj in emailFolder.Items)
{
if(obj is MailItem)
{
MailItem item = (MailItem)obj;
Console.WriteLine(item.SenderEmailAddress + " " + item.Subject + "\n" + item.Body);
}
}
item.SenderEmailAddress is returning a very strange address for multiple recipient, also if i have made any group of people and send mail to them then also.
So any one can guide how to read those multiple address and also the name of the group.
Thanks in advance.

Try this
Outlook.Application app = new Outlook.Application();
Outlook.NameSpace outlookNs = app.GetNamespace("MAPI");
outlookNs.AddStore(#"D:\pst\Test.pst");
Outlook.MAPIFolder emailFolder = outlookNs.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderSentMail);
List<MailItem> lstMails = emailFolder.Items.OfType<MailItem>().Where(x=>x.SenderEmailAddress.Contains("hari")).Select(x=>x).ToList();
foreach (Object obj in emailFolder.Items)
{
if(obj is MailItem)
{
MailItem item = (MailItem)obj;
String user=String.Empty;
foreach (Object obj1 in ((dynamic)item).Recipients)
{
user += ((dynamic)obj1).Name + ";";
}
Console.WriteLine(user + " " + item.Subject + "\n" + item.Body);
}
}
This has worked for me.

As a note, do not use LINQ with Outlook. It might look cool in your code, but you need to realize that all the processing is done on the client side, it is not any different from explicitly looping through all items in the folder.
Use Items.Restrict or Find/FindNext - the search will be performed by the store provider.

Related

How to open an email, in the sent box, with C#?

My application sends a templated email with information from a datagridview.
I am trying to send a follow up email.
I'd like the app to open the existing email from my sent items folder (using Outlook 365/Outlook 16) and add text to the top of the already existing email so there's a clear chain of communication.
I have code to find the email within the sent box.
How do I open/display that email so text can be added onto it before it's forwarded?
What I have so far:
private void dvgLogs_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
label4.Visible = true;
Outlook.Application app = new Outlook.Application();
Outlook.Selection item = app.ActiveExplorer().Selection;
Outlook.Folder sentItems = (Outlook.Folder)app.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
Outlook.Items items = sentItems.Items;
Outlook.MailItem mailItem = null;
object folderItem;
string subjectName = "Regarding " + dgvTickets.CurrentRow.Cells[2].Value.ToString() + " #" + dgvTickets.CurrentRow.Cells[3].Value.ToString();
string filter = "[Subject] = " + subjectName;
folderItem = items.Find(filter);
while (folderItem != null)
{
mailItem = folderItem as Outlook.MailItem;
if (mailItem != null)
{
subjectName += mailItem.Subject;
}
folderItem = items.FindNext();
}
subjectName = " The following e-mail messages were found: " + subjectName;
MessageBox.Show(subjectName);
lblFoundEmail.Text = subjectName;
}
This seems to find the email and let me know that it found it in my messagebox.
I want it to open the found email.
EDIT
This code is not quite what I want, but it's better than the above code where my email was not being displayed.
private void button1_Click(object sender, EventArgs e)
{
Outlook.Application app = new Outlook.Application();
Outlook.Selection item = app.ActiveExplorer().Selection;
Outlook.Folder sentItems = (Outlook.Folder)app.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
if (app.Session.DefaultStore.IsInstantSearchEnabled)
{
Outlook.Explorer explorer = (Explorer)app.Explorers.Add(item.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail)
as Outlook.Folder, Outlook.OlFolderDisplayMode.olFolderDisplayNormal);
string subjectName = "Regarding " + dgvTickets.CurrentRow.Cells[2].Value.ToString() + " #" + dgvTickets.CurrentRow.Cells[3].Value.ToString();
string filter = "subject:" + "\"" + subjectName + "\"";
explorer.Search(filter, Outlook.OlSearchScope.olSearchScopeAllFolders);
explorer.Display();
}
}
The above code appears to pop open a new Outlook window, and perform the search (which is more than what it was doing, also, it does find the sent email each time), however it doesn't display the email, instead just another instance of Outlook with the performed search.
I'd like it to use the Outlook window that's already open, and then display the found email.

Adding table using mailto and windows forms

I want to open mail to and inside the body of my email I want to create a table and insert values inside my model. So I execute outlook like this:
var mail = $"mailto:test#test.com?subject=ProjectListTest&body={finalString}";
My question is, how can I create a table and add to body of mailto?
Table headers: Name, Customer
so inside each row I want to use something like:
var finalString = string.Empty;
foreach(var customer in CustomerList)
{
finalString = finalString + customer.Name + customer.CustomerKey
}
Is it possible to achieve this? what is the correct format to create a table in Outlook. Regards
pIf the table would be created using the html mail body format, then you can use the following method to generate it:
public string GenerateMailBodyWithTable(List<Customer> customers)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append($"<html>{ Environment.NewLine }<body>{ Environment.NewLine }");
if (customers.Count > 0)
{
stringBuilder.Append($"<table><tr><th>Name</th><th>Key</th></tr>{ Environment.NewLine }");
foreach (Customer customer in customers)
{
stringBuilder.Append($"<tr><th>{ customer._name }</th><th>{ customer._key }</th></tr>{ Environment.NewLine }");
}
stringBuilder.Append($"<table>{ Environment.NewLine }");
}
else
{
stringBuilder.Append($"<p>No customers<p>{ Environment.NewLine }");
}
stringBuilder.Append($"</html>{ Environment.NewLine }</body>");
return stringBuilder.ToString();
}
After generating the html body you can perform the following action to fill the mailbody:
Outlook.Application outlookApp = new Outlook.Application();
Outlook.MailItem mailMessage = (Outlook.MailItem)outlookApp.CreateItem(Outlook.OlItemType.olMailItem);
mailMessage.HTMLBody = GenerateMailBodyWithTable(customers);
mailMessage.Display(true);
Don't forget to place this using statement:
using Outlook = Microsoft.Office.Interop.Outlook;
First at all, you have to create your custom HTML:
string finalString = "<table><tr><td><b>Name</b></td><td><b>Customer</b></td></tr>";
foreach(var customer in CustomerList)
{
finalString += "<tr><td>" + customer.Name + "</td><td>" + customer.CustomerKey + "</td></tr>";
}
finalString += "</table>";
If you are using WinForms and you want to send an email with this body, you can use MailMessage Class from System.Net.Mail and sending it with SmtpClient. This way:
MailMessage mail = new MailMessage("from", "mailto", "Subject", finalString);
mail.IsBodyHtml = true; //Important
SmtpClient smtp = new SmtpClient("serverSMTP");
smtp.EnableSsl = USE_SSL;
smtp.Port = YOUR_PORT;
smtp.Credentials = new System.Net.NetworkCredential("email", "password");
smtp.Send(correo);
If you want to simulate a "mailto" action, you can use:
string command = $"mailto:test#test.com?subject=ProjectListTest&body={finalString}";
Process.Start(command);
Regards

How do I limit the number objects I iterate over when Linq is not supported?

How do I limit my foreach loop to the first 500 emails? It seems Linq and Lambda is not supported on emailFolder.Items. Is there another approach that I should be taking?
Outlook.Application app = new Outlook.Application();
Outlook.NameSpace outlookNs = app.GetNamespace("MAPI");
Outlook.MAPIFolder emailFolder = outlookNs.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
foreach(Object item in emailFolder.Items)
{
Outlook.MailItem _item = (Outlook.MailItem)item;
Console.WriteLine(_item.SenderEmailAddress + " " + _item.Subject + "\n" + _item.Body);
}
Linq only works on types that are implement the interface IEnumerable<T>. Older collections implement the non-generic interface IEnumerable, which does not work with Linq. There are some extensions methods which "convert" these collections to linqable collections:
To convert Items to a something linqable, use:
emailFolder.Items.Cast<Outlook.MailItem>()....
* EDITED after suggestion of Spender & Alexei *
If you are using the try-catch to suppress an invalid cast, resulting in only items of a specific type, try:
emailFolder.Items.OfType<Outlook.MailItem>()....
This could lead to:
Outlook.Application app = new Outlook.Application();
Outlook.NameSpace outlookNs = app.GetNamespace("MAPI");
Outlook.MAPIFolder emailFolder = outlookNs.GetDefaultFolder (Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
foreach(Outlook.MailItemitem _item in emailFolder.Items.OfType<Outlook.MailItem>().Take(500))
{
Console.WriteLine(_item.SenderEmailAddress + " " + _item.Subject + "\n" + _item.Body);
}
Use the .OfType extension method to grab a typed IEnumerable<Outlook.MailItem> of all the Outlook.MailItem instances in the Items collection.
mapifolder.Items.OfType<Outlook.MailItem>()
...and you can return to Linq-world!
Firstly, if you're using .NET framework version 4 or later, you should make sure the next line is in the file header (the "using" section):
using System.Linq;
Otherwise, there's always the following:
int count=0;
foreach(Object item in emailFolder.Items)
{
try
{
Outlook.MailItem _item = (Outlook.MailItem)item;
Console.WriteLine(_item.SenderEmailAddress + " " + _item.Subject + "\n" + _item.Body);
++count;
if (count == 500)
break;
}
catch(Exception ex)
{
}
}

Sending Email through Outlook 2010 via C#

I am trying to send an email from inside my C# console App. I have added the references and using statements but it seems I have not added everything I need. This is the first time I have ever attempted to do this so I figure there is something I have forgotten.
I got this code snippet from the MSDN site http://msdn.microsoft.com/en-us/library/vstudio/ms269113(v=vs.100).aspx
Here is the code that I am getting issues with in VS 2010
using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Runtime.InteropServices;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
namespace FileOrganizer
{
class Program
{
private void CreateMailItem()
{
//Outlook.MailItem mailItem = (Outlook.MailItem)
// this.Application.CreateItem(Outlook.OlItemType.olMailItem);
Outlook.Application app = new Outlook.Application();
Outlook.MailItem mailItem = app.CreateItem(Outlook.OlItemType.olMailItem);
mailItem.Subject = "This is the subject";
mailItem.To = "someone#example.com";
mailItem.Body = "This is the message.";
mailItem.Attachments.Add(logPath);//logPath is a string holding path to the log.txt file
mailItem.Importance = Outlook.OlImportance.olImportanceHigh;
mailItem.Display(false);
}
}
}
replace the line
Outlook.MailItem mailItem = (Outlook.MailItem)
this.Application.CreateItem(Outlook.OlItemType.olMailItem);
with
Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.MailItem mailItem = app.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);
Hope this helps,
This is how you can send an email via Microsoft Office Outlook. In my case I was using Office 2010, but I suppose it should work with newer versions.
The upvoted sample above just displays the message. It does not send it out. Moreover it doesn't compile.
So first you need to add these references to your .NET project:
Like I said in my comment to his OP:
You will need to add the following references: (1) From .NET tab add
Microsoft.Office.Tools.Outlook for runtime v.4.0.*, then (2) again
from .NET tab add Microsoft.Office.Interop.Outlook for version
14.0.0.0 in my case, and (3) COM object Microsoft Office 12.0 Object Library for Microsoft.Office.Core.
Then here's the code to send out emails:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Configuration;
using System.IO;
using System.Net.Mail;
using System.Runtime.InteropServices;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
public enum BodyType
{
PlainText,
RTF,
HTML
}
//....
public static bool sendEmailViaOutlook(string sFromAddress, string sToAddress, string sCc, string sSubject, string sBody, BodyType bodyType, List<string> arrAttachments = null, string sBcc = null)
{
//Send email via Office Outlook 2010
//'sFromAddress' = email address sending from (ex: "me#somewhere.com") -- this account must exist in Outlook. Only one email address is allowed!
//'sToAddress' = email address sending to. Can be multiple. In that case separate with semicolons or commas. (ex: "recipient#gmail.com", or "recipient1#gmail.com; recipient2#gmail.com")
//'sCc' = email address sending to as Carbon Copy option. Can be multiple. In that case separate with semicolons or commas. (ex: "recipient#gmail.com", or "recipient1#gmail.com; recipient2#gmail.com")
//'sSubject' = email subject as plain text
//'sBody' = email body. Type of data depends on 'bodyType'
//'bodyType' = type of text in 'sBody': plain text, HTML or RTF
//'arrAttachments' = if not null, must be a list of absolute file paths to attach to the email
//'sBcc' = single email address to use as a Blind Carbon Copy, or null not to use
//RETURN:
// = true if success
bool bRes = false;
try
{
//Get Outlook COM objects
Outlook.Application app = new Outlook.Application();
Outlook.MailItem newMail = (Outlook.MailItem)app.CreateItem(Outlook.OlItemType.olMailItem);
//Parse 'sToAddress'
if (!string.IsNullOrWhiteSpace(sToAddress))
{
string[] arrAddTos = sToAddress.Split(new char[] { ';', ',' });
foreach (string strAddr in arrAddTos)
{
if (!string.IsNullOrWhiteSpace(strAddr) &&
strAddr.IndexOf('#') != -1)
{
newMail.Recipients.Add(strAddr.Trim());
}
else
throw new Exception("Bad to-address: " + sToAddress);
}
}
else
throw new Exception("Must specify to-address");
//Parse 'sCc'
if (!string.IsNullOrWhiteSpace(sCc))
{
string[] arrAddTos = sCc.Split(new char[] { ';', ',' });
foreach (string strAddr in arrAddTos)
{
if (!string.IsNullOrWhiteSpace(strAddr) &&
strAddr.IndexOf('#') != -1)
{
newMail.Recipients.Add(strAddr.Trim());
}
else
throw new Exception("Bad CC-address: " + sCc);
}
}
//Is BCC empty?
if (!string.IsNullOrWhiteSpace(sBcc))
{
newMail.BCC = sBcc.Trim();
}
//Resolve all recepients
if (!newMail.Recipients.ResolveAll())
{
throw new Exception("Failed to resolve all recipients: " + sToAddress + ";" + sCc);
}
//Set type of message
switch (bodyType)
{
case BodyType.HTML:
newMail.HTMLBody = sBody;
break;
case BodyType.RTF:
newMail.RTFBody = sBody;
break;
case BodyType.PlainText:
newMail.Body = sBody;
break;
default:
throw new Exception("Bad email body type: " + bodyType);
}
if (arrAttachments != null)
{
//Add attachments
foreach (string strPath in arrAttachments)
{
if (File.Exists(strPath))
{
newMail.Attachments.Add(strPath);
}
else
throw new Exception("Attachment file is not found: \"" + strPath + "\"");
}
}
//Add subject
if(!string.IsNullOrWhiteSpace(sSubject))
newMail.Subject = sSubject;
Outlook.Accounts accounts = app.Session.Accounts;
Outlook.Account acc = null;
//Look for our account in the Outlook
foreach (Outlook.Account account in accounts)
{
if (account.SmtpAddress.Equals(sFromAddress, StringComparison.CurrentCultureIgnoreCase))
{
//Use it
acc = account;
break;
}
}
//Did we get the account
if (acc != null)
{
//Use this account to send the e-mail.
newMail.SendUsingAccount = acc;
//And send it
((Outlook._MailItem)newMail).Send();
//Done
bRes = true;
}
else
{
throw new Exception("Account does not exist in Outlook: " + sFromAddress);
}
}
catch (Exception ex)
{
Console.WriteLine("ERROR: Failed to send mail: " + ex.Message);
}
return bRes;
}
And here's how you'd use it:
List<string> arrAttachFiles = new List<string>() { #"C:\Users\User\Desktop\Picture.png" };
bool bRes = sendEmailViaOutlook("senders_email#somewhere.com",
"john.doe#hotmail.com, jane_smith#gmail.com", null,
"Test email from script - " + DateTime.Now.ToString(),
"My message body - " + DateTime.Now.ToString(),
BodyType.PlainText,
arrAttachFiles,
null);
You need to cast the
app.CreateItem(Outlook.OlItemType.olMailItem)
object in
Outlook.MailItem mailItem = app.CreateItem(Outlook.OlItemType.olMailItem)
to
Outlook.MailItem type
since no implicit casting is available.
Replace
Outlook.MailItem mailItem = app.CreateItem(Outlook.OlItemType.olMailItem);
with
Outlook.MailItem mailItem = (Outlook.MailItem)app.CreateItem(Outlook.OlItemType.olMailItem);

Microsoft Outlook adding cc to email

I currently have existing code that automates and email and sends files. I now need to add a cc. I have looked all over, but can't seem to find out with my existing code. Any help would be greatly appreciated. Thank you.
private void button13_Click(object sender, EventArgs e)
{
//Send Routing and Drawing to Dan
// 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);
//Add a recipient
Outlook.Recipient oRecip = (Outlook.Recipient)oMsg.Recipients.Add("email#email.com");
oRecip.Resolve();
//Set the basic properties.
oMsg.Subject = "Job # " + textBox9.Text + " Release (" + textBox1.Text + ")";
oMsg.HTMLBody = "<html><body>";
oMsg.HTMLBody += "Job # " + textBox9.Text + " is ready for release attached is the Print and Routing (" + textBox1.Text + ")";
oMsg.HTMLBody += "<p><a href='C:\\Users\\RussellS\\Desktop\\Russell Eng Reference\\" + textBox1.Text + ".PDF'>" + textBox1.Text + " Drawing";
oMsg.HTMLBody += "<p><a href='C:\\Users\\RussellS\\Desktop\\" + textBox1.Text + ".PDF'>" + textBox1.Text + " Routing" + "</a></p></body></html>";
//Send the message
oMsg.Send();
//Explicitly release objects.
oRecip = null;
oMsg = null;
oApp = null;
MessageBox.Show(textBox1.Text + " Print and Routing Sent");
}
According to MSDN there's a CC property on the MailItem class.
string CC { get; set; }
Which can be used to set the names of the CC recipients.
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._mailitem.cc.aspx
To modify the recipients you can add them to the Recipients collection:
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.recipients.aspx
Which you would use like:
oMsg.Recipients.Add("foo#bar.com");
Please follow this code for adding CC and BCC:
private void SetRecipientTypeForMail()
{
Outlook.MailItem mail = Application.CreateItem(
Outlook.OlItemType.olMailItem) as Outlook.MailItem;
mail.Subject = "Sample Message";
Outlook.Recipient recipTo =
mail.Recipients.Add("someone#example.com");
recipTo.Type = (int)Outlook.OlMailRecipientType.olTo;
Outlook.Recipient recipCc =
mail.Recipients.Add("someonecc#example.com");
recipCc.Type = (int)Outlook.OlMailRecipientType.olCC;
Outlook.Recipient recipBcc =
mail.Recipients.Add("someonebcc#example.com");
recipBcc.Type = (int)Outlook.OlMailRecipientType.olBCC;
mail.Recipients.ResolveAll();
mail.Display(false);
}

Categories