Exchange EWS get BCC Recipients - c#

I am using EWS to create a StreamingSubscription on an inbox. It is listening for the NewMail event. I am able to pull the From Address, Subject, Body, To Address, CC Address but not the BCC Address. Is there any way to see this list?
CODE:
static void OnEvent(object sender, NotificationEventArgs args)
{
String from = null;
String subject = null;
String body = null;
String to = null;
StreamingSubscription subscription = args.Subscription;
// Loop Through All Item-Related Events
foreach (NotificationEvent notification in args.Events)
{
ItemEvent item = (ItemEvent)notification;
PropertySet propertySet = new PropertySet(ItemSchema.UniqueBody);
propertySet.RequestedBodyType = BodyType.Text;
propertySet.BasePropertySet = BasePropertySet.FirstClassProperties;
// Parse Email
EmailMessage message = EmailMessage.Bind(service, item.ItemId, propertySet);
from = message.From.Address;
subject = message.Subject;
body = message.Body.Text;
if (message.ToRecipients.Count > 0)
{
to = message.ToRecipients[0].Address;
body += "\n TO FIELD";
}
else if (message.CcRecipients.Count > 0)
{
to = message.CcRecipients[0].Address;
body += "\n CC FIELD";
}
/************** Does not work! BccRecipients is always empty *****************/
else if (message.BccRecipients.Count > 0)
{
to = message.BccRecipients[0].Address;
body += "\n BCC FIELD";
}
/************* REST OF CODE ************************/
}
}

That would kind of defeat the point of a blind-carbon-copy. I dont believe it can be done.

Consider using the Journaling feature of Exchange. This uses something called "Envelope Journaling" which includes BCC information for messages within the Exchange environment.
For everything that comes from external sources (gmail) no BCC information is available.

This might help:
http://gsexdev.blogspot.com/2011/06/processing-bccs-in-exchange-transport.html

Related

Accessing email properties in Exchange web server managed API

I'm a complete newbie to EWS, but am trying to convert a happily functioning IMAP program into EWS & am having problems accessing simple fields in the managed API, e.g. From, Sender, BodyType. Can anyone spot what I am doing wrong? Many thanks folks.
ItemView view = new ItemView(99);
SearchFilter.Exists filter = new SearchFilter.Exists(EmailMessageSchema.Id);
FindItemsResults<Item> inboxMessageList = service.FindItems(WellKnownFolderName.Inbox, view);
Console.WriteLine("Inbox message count: " + inboxMessageList.TotalCount);
int messageCounter = 1;
//message loop
foreach (Item thisMessage in inboxMessageList)
{
//Collect info about current email message
Item thisItem = Item.Bind(service, thisMessage.Id);
Console.WriteLine("Current message ID: " + thisMessage.Id);
string uniqueID = "EMAIL-" + DateTime.UtcNow.ToString("yyyyMMdd-HHmmss-fff");
string messageTo = thisItem.DisplayTo;
string messageCC = thisItem.DisplayCc;
string messageFrom = //cant get this to work
string messageSubject = thisItem.Subject;
string messageDate = thisMessage.DateTimeReceived.ToString();
int noOfAttachments = 0;
Boolean messageHasAttachments = thisMessage.HasAttachments;
if (messageHasAttachments) noOfAttachments = thisMessage.Attachments.Count();
string isBodyHtml = //cant seem to implement this either
Boolean domainblacklistResult = fn.CheckIfDomainBlacklisted(messageFrom);
Boolean emailblacklistResult = fn.CheckIfEmailBlacklisted(messageFrom);
To access information about the email message, you need to bind it as an EmailMessage, instead of as an Item. Example:
EmailMessage message = EmailMessage.Bind(service, thisMessage.Id);

how to find mail that was send by MailItem.Display()

I have following requirement :
Allow the user to drag & drop an email from outlook to a datagrid
Prepare a reply mail, and show it so the user can review and send
After sending, also fetch the send mail and put it into the datagrid
The drag/drop I have working
Preparing the replay email and showing it to the user I also have working, with this code :
MailItem mail = GetMailBySubject(dateReceived, subject);
if (mail != null)
{
MailItem mailReply = mail.ReplyAll();
// add text and stuff to mailReply...
mailReply.Display();
}
This will open a window in outlook, as if the user clicked reply in outlook.
Now I am stuck with the 3th requirement,
after the user send the reply email, I need somehow to find this email in outlook to add it to my datagrid.
But I have no clue on how to do that.
All I have is the original mail that is been used to prepare the reply.
Is there a way to find the reply with only this, or is this maybe a complete wrong approach ?
To make it more difficult is that I have to show the reply email NON Modal, so I have no trigger when the user clicked on send in outlook.
for reference, here is the code for GetMailBySubject
private MailItem GetMailBySubject(DateTime dateReceived, string subject)
{
MailItem Result = null;
Microsoft.Office.Interop.Outlook.Application OutlookIns = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace olNamespace = OutlookIns.GetNamespace("MAPI");
MAPIFolder myInbox = olNamespace.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
Items items = myInbox.Items;
int count = items.Count;
MailItem mail = null;
int i = 1; //DO NOT START ON 0
while ((i < count) && (Result == null))
{
if (items[i] is MailItem)
{
mail = (MailItem)items[i];
if ((mail.ReceivedTime.ToString("yyyyMMdd hh:mm:ss") == dateReceived.ToString("yyyyMMdd hh:mm:ss")) && (mail.Subject == subject))
{
Result = mail;
}
}
i++;
}
return Result;
}
EDIT
I tried this code as suggested, but the Items.ItemAdd event is not firing.
So I must still be doing something wrong but I cant see it
this is my code now
MailItem mail = GetMailBySubject((DateTime)sentOn, msg.Subject);
if (mail != null)
{
MailItem mailReply = mail.ReplyAll();
mailReply.HTMLBody = GetDefaultReplyText() + Environment.NewLine + mailReply.HTMLBody;
Guid guid = Guid.NewGuid();
UserProperties mailUserProperties = null;
UserProperty mailUserProperty = null;
mailUserProperties = mailReply.UserProperties;
mailUserProperty = mailUserProperties.Add("myproperty", OlUserPropertyType.olText);
mailUserProperty.Value = guid.ToString(); ;
// the code below gives error "The property cannot be parsed or has an invalid format"
//mailReply.PropertyAccessor.SetProperty("myproperty", guid.ToString());
mailReply.Display();
}
private MailItem GetMailBySubject(DateTime dateReceived, string subject)
{
MailItem Result = null;
Microsoft.Office.Interop.Outlook.Application OutlookIns = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace olNamespace = OutlookIns.GetNamespace("MAPI");
MAPIFolder myInbox = olNamespace.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
Items items = myInbox.Items;
int count = items.Count;
MailItem mail = null;
int i = 1; //DO NOT START ON 0
while ((i < count) && (Result == null))
{
if (items[i] is MailItem)
{
mail = (MailItem)items[i];
if ((mail.ReceivedTime.ToString("yyyyMMdd hh:mm:ss") == dateReceived.ToString("yyyyMMdd hh:mm:ss")) && (mail.Subject == subject))
{
Result = mail;
MAPIFolder mySent = olNamespace.GetDefaultFolder(OlDefaultFolders.olFolderSentMail);
mySent.Items.ItemAdd += Items_SentMailItemAdd;
}
}
i++;
}
return Result;
}
and finally
private void Items_SentMailItemAdd(object Item)
{
//throw new NotImplementedException();
; // this event is never fired
}
You can use the Items.ItemAdd event on the Sent Items folder. To check if that is your message, set a custom property on the message that you create and display. You can use MailItem.UserProperties.Add, but that can force the message to be sent in the TNEF format. To prevent that from happening, you can use MailItem.PropertyAccessro.SetProperty to set a named MAPI property without using the UserProperties collection. You can set a test user property and look at its DASL name (to be used by SetProperty) with OutlookSpy (I am its author - select the message, click IMessage button, select your custom property, see the DASL edit box).

Is there a way to read an reply of a mail using Gmail API

foreach (var part in emailInfoResponse.Result.Payload.Parts)
{
if (part.Parts != null)
foreach (var innerPart in part.Parts)
{
if (innerPart.MimeType == "text/plain")
{
body = innerPart.Body.Data;
}
}
}
I am successfully reading the body ONLY of the main mail. It is not taking the data from the reply messages assigned to the mail,
any ideas how I can I read the replies to the mail too? Or even if there is a way to take only the replies of a specific mail
To get later / other messages in a conversation, you need to retrieve the source thread:
String threadID = emailInfoResponse.Result.ThreadId;
Thread thread = service.Users.Threads.Get(userID, threadID).Execute();
foreach( var msg in thread.Messages )
{
/* your code for each message */
}
Per the Gmail message reference, messages can share a threadId if they have both the correct headers and the same subject. Otherwise, they will be on different email threads.
You'd probably want to refactor a bit and start from a ThreadList. This way, you can find all conversations that match a specific input query (to find only the messages that correspond to these client lists):
Make data storage object: Dictionary<String, Container>, where the string is the company (from the email subject, or wherever), and the container probably only needs unique values so HashSet or similar.
Page through the ThreadList
For each thread
Page through messages
For each message, if the first message, get the subject i.e. company name (all messages have to share a subject in the same thread).
Then append the clients to the data storage object based on the subject (company name).
Construct your database records from the data storage object as appropriate.
public static MimeKit.MimeMessage Reply(MimeKit.MimeMessage message, bool replyToAll)
{
var reply = new MimeKit.MimeMessage();
if (message.ReplyTo.Count > 0)
{
reply.To.AddRange(message.ReplyTo);
}
else if (message.From.Count > 0)
{
reply.To.AddRange(message.From);
}
else if (message.Sender != null)
{
reply.To.Add(message.Sender);
}
if (replyToAll)
{
reply.To.AddRange(message.To);
reply.Cc.AddRange(message.Cc);
}
if (!message.Subject.StartsWith("Re:", StringComparison.OrdinalIgnoreCase))
reply.Subject = "Re:" + message.Subject;
else
reply.Subject = message.Subject;
if (!string.IsNullOrEmpty(message.MessageId))
{
reply.InReplyTo = message.MessageId;
foreach (var id in message.References)
reply.References.Add(id);
reply.References.Add(message.MessageId);
}
using (var quoted = new StringWriter())
{
var sender = message.Sender ?? message.From.Mailboxes.FirstOrDefault();
quoted.WriteLine("On {0}, {1} wrote:", message.Date.ToString("f"), !string.IsNullOrEmpty(sender.Name) ? sender.Name : sender.Address);
using (var reader = new StringReader(message.TextBody))
{
string line;
while ((line = reader.ReadLine()) != null)
{
quoted.Write("> ");
quoted.WriteLine(line);
}
}
reply.Body = new MimeKit.TextPart("plain")
{
Text = quoted.ToString()
};
}
return reply;
}

C# - Send email with inline attachment WITHOUT Outlook's paperclip icon?

I have a system that sends emails with inline pictures. The problem is how Outlook 2013 displays the attachments. Can I update my code in a way that tells outlook not to display the paperclip icon seen here?
The idea is that I only want to display this icon when full sized pictures are attached. Not inline attachments.
Here's the code that generates the email. Create a basic console app, specify your To / mailserver / picture path, and run.
static void Main(string[] args)
{
Console.WriteLine("Prepping email message....");
var subject = "Test Subject With Inline";
var message = "<p>This is a test message.</p><br/><br/><p>[CompanyLogo]</p>";
var to = new List<string>();
to.Add("My.Name#company.com");
Console.WriteLine("Sending email message....");
if (SendMessageToFrom(subject, message, to, new List<string>()))
{
Console.WriteLine("Email sent! Check your inbox.");
}
else
{
Console.WriteLine("Error sending email!");
}
}
public static bool SendMessageToFrom(String subject, String message, List<String> to, List<String> cc)
{
try
{
// Construct the email
var sendMessage = new MailMessage()
{
IsBodyHtml = true,
From = new MailAddress("noreply#company.com"),
Subject = subject,
Body = message
};
if (sendMessage.Body.Contains("[CompanyLogo]"))
{
sendMessage.AlternateViews.Add(EmbedLogo(sendMessage.Body));
}
// Add the list of recipients
foreach (var recipient in to)
{
sendMessage.To.Add(recipient);
}
foreach (var recipient in cc)
{
sendMessage.CC.Add(recipient);
}
//Specify the SMTP server
var smtpServerName = "mailserver.company.com";
var mailClient = new SmtpClient(smtpServerName);
mailClient.Send(sendMessage);
return true;
}
catch
{
throw;
}
}
private static AlternateView EmbedLogo(string html)
{
var inline = new LinkedResource("img\\company-logo.jpg");
inline.ContentId = Guid.NewGuid().ToString();
html = html.Replace("[CompanyLogo]", string.Format(#"<img src='cid:{0}'/>", inline.ContentId));
var result = AlternateView.CreateAlternateViewFromString(html, null, System.Net.Mime.MediaTypeNames.Text.Html);
result.LinkedResources.Add(inline);
return result;
}
Update: Here's the code that did the trick:
private static MailMessage EmbedLogo(MailMessage mail)
{
var inline = new Attachment("img\\company-logo.jpg");
inline.ContentId = Guid.NewGuid().ToString();
inline.ContentDisposition.Inline = true;
inline.ContentDisposition.DispositionType = DispositionTypeNames.Inline;
mail.Body = mail.Body.Replace("[CompanyLogo]", string.Format(#"<img src='cid:{0}'/>", inline.ContentId));
mail.Attachments.Add(inline);
return mail;
}
And I also updated the main method to this:
if (sendMessage.Body.Contains("[CompanyLogo]"))
{
sendMessage = EmbedLogo(sendMessage);
}
Make sure your attachments have the Content-ID MIME header and the message's HTML body refers to them using the cid attribute : <img src="cid:xyz"> (where xyz is the value of the Content-ID MIME header).

Sending multiple e-mails using outlook MailItem in loop

Hello I am developing an outlook Add-on, as part of the work flow it should take the mailItem body and subject, and for each recipient it should change the body of message according to recipient e-mail.
The problem is that it just sends the first e-mail and after Send(); it does not send the e-mail to other recipients
Outlook.Application application = Globals.ThisAddIn.Application;
Outlook.Inspector inspector = application.ActiveInspector();
Outlook.MailItem myMailItem = (Outlook.MailItem)inspector.CurrentItem;
myMailItem.Save();
if (myMailItem != null)
{
myMailItem.Save();
PorceesData(myMailItem);
}
..
..
..
..
private void ProcessData(MailItem oMailItem)
{
Recipients recipients = oMailItem.Recipients;
string Body = oMailItem.Body;
string To = oMailItem.To;
string CC = oMailItem.CC;
string bcc = oMailItem.BCC;
foreach (Recipient r in recipients)
{
if (r.Resolve() == true)
{
string msg = "Hello open the attached file (msg.html);
string address = r.Address;
oMailItem.Body = msg;
oMailItem.To = address;
oMailItem.Subject = "my subject"
foreach (Attachment t in oMailItem.Attachments)
{
t.Delete();
}
oMailItem.Attachments.Add(#"mydirectory");
oMailItem.Send();
}
_MailItem.Send() closes the current inspector. This isn't in the _MailItem.Send documentation, but is the actual Outlook implementation. You should probably come up with another approach. I'd suggest creating a new MailItem instance for each message you wish to send.
You can create a new MailItem using...
Outlook.MailItem eMail = (Outlook.MailItem)
Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem);
eMail.Subject = subject;
eMail.To = toEmail;
eMail.Body = body;
eMail.Importance = Outlook.OlImportance.olImportanceLow;
((Outlook._MailItem)eMail).Send();
After sending to all recipients you can manually close the current inspector using the following (Send() implicitly calls this method)
((Outlook._MailItem)myMailItem).Close(Outlook.OlInspectorClose.olDiscard)

Categories

Resources