Get sender email address from attachment - c#

Question
How would I look at the attachment properties using EWS (Exchange 2013, C#) and retrieve the original sender's email address? Not the email address of the current sender, but the sender of the email that is attached to this email.
What I Did
Lots of googling has shown me only how to retrieve the sender of the current email and not the attachement. I do this by
//get sender of email to TR
EmailMessage mes = (EmailMessage)item;
String sender = mes.Sender.Address;
Request
Thoughts? Links? Sample code? I am looking for anything right now that I can use to help me load up the attachment and pull the sender email address. Thanks!

You want to fetch details on attached emails right?
Try This Code Snippet? Assuming _ewsService is a correctly bound service client.
var results = _ewsService.FindItems(WellKnownFolderName.Inbox, new ItemView(100)); //fetch 100 random emails from inbox
foreach (var entry in results.Items)
{
if (entry is EmailMessage)
{
var temp = EmailMessage.Bind(_service, entry.Id);
if (entry.HasAttachments)
{
temp.Load(new PropertySet(EmailMessageSchema.Attachments));
foreach (var singleItem in temp.Attachments)
{
if (singleItem is ItemAttachment)
{
var attachedMail = singleItem as ItemAttachment;
attachedMail.Load();
Console.WriteLine(attachedMail.Item is EmailMessage);
var workingMessage = attachedMail.Item as EmailMessage; //this should give you from, subject, body etc etc.
}
}
}
}
}

Related

Retrieve unread emails and leave them as unread in inbox

I'm using GemBox.Email and I'm retrieving unread emails from my inbox like this:
using (var imap = new ImapClient("imap.gmail.com"))
{
imap.Connect();
imap.Authenticate("username", "password");
imap.SelectInbox();
IEnumerable<string> unreadUids = imap.ListMessages()
.Where(info => !info.Flags.Contains(ImapMessageFlags.Seen))
.Select(info => info.Uid);
foreach (string uid in unreadUids)
{
MailMessage unreadEmail = imap.GetMessage(uid);
unreadEmail.Save(uid + ".eml");
}
}
The code is from the Receive example, but the problem is that after retrieving them they end up being marked as read in my inbox.
How can I prevent this from happening?
I want to download them with ImapClient and leave them as unread on email server.
EDIT (2021-01-19):
Please try again with the latest version from the BugFixes page or from NuGet.
The latest version provides ImapClient.PeekMessage methods which you can use like this:
using (var imap = new ImapClient("imap.gmail.com"))
{
imap.Connect();
imap.Authenticate("username", "password");
imap.SelectInbox();
foreach (string uid in imap.SearchMessageUids("UNSEEN"))
{
MailMessage unreadEmail = imap.PeekMessage(uid);
unreadEmail.Save(uid + ".eml");
}
}
ORIGINAL:
When retrieving an email, most servers will mark it with the "SEEN" flag. If you want to leave an email as unread then you can just remove the flag.
Also, instead of using ImapClient.ListMessages you could use ImapClient.SearchMessageUids to get IDs of unread emails.
So, try the following:
using (var imap = new ImapClient("imap.gmail.com"))
{
imap.Connect();
imap.Authenticate("username", "password");
imap.SelectInbox();
// Get IDs of unread emails.
IEnumerable<string> unreadUids = imap.SearchMessageUids("UNSEEN");
foreach (string uid in unreadUids)
{
MailMessage unreadEmail = imap.GetMessage(uid);
unreadEmail.Save(uid + ".eml");
// Remove "SEEN" flag from read email.
imap.RemoveMessageFlags(uid, ImapMessageFlags.Seen);
}
}

Email to group using EWS C#

I'm using ExchangeWebServices C#.
I'm trying to send an email to distributio list, so
I'm created a group as follow:
private void CreateGroup(ExchangeService service)
{
// Create a new contact group object.
ContactGroup myContactGroup = new ContactGroup(service);
// Give the group a name.
myContactGroup.DisplayName = "TestContactGroup";
// Add some members to the group.
myContactGroup.Members.Add(new GroupMember("Euser#mydomain.com"));
myContactGroup.Members.Add(new GroupMember("Euser1#mydomain.com"));
myContactGroup.Members.Add(new GroupMember("Euser2#mydomain.com"));
// Save the group.
myContactGroup.Save();
}
Now I'm trying to send email to this group, how can i do that?
What i'm tried:
EmailMessage email = new EmailMessage(service);
email.ToRecipients.Add("TestContactGroup");//Throw an exception "At least one recipient isn't valid."
//email.ToRecipients.Add("TestContactGroup#mydomain.com");//"Return" the mail that "The email address you entered couldn't be found."
email.Subject = "MySubject";
email.Body = new MessageBody("MyBody");
// Send the mail
email.Send();
If I'm trying to send to TestContactGroup i'm got an exception:
"At least one recipient isn't valid."
And if I'm trying to send to TestContactGroup#mydomain.com I'm got an email that the mail isn't found.
So, how can i send an email to group list that I'm crated? Or another way to create distribution list with EWS?
Thanks
Problem solved.
I'm just need to add the group id as follow:
myContactGroup.Id = grpId;
I'm get my group id as follow:
// Instantiate the item view with the number of items to retrieve from the Contacts folder.
ItemView view = new ItemView(9999);
// Request the items in the Contacts folder that have the properties that you selected.
FindItemsResults<Item> contactItems = service.FindItems(WellKnownFolderName.Contacts, view);
string groupId = string.Empty;
List<ItemId> groupItemIds = new List<ItemId>();
// Loop through all contacts
foreach (Item item in contactItems)
{
//Check to see if ContactGroup
if (item is ContactGroup)
{
//Get the contact group
ContactGroup contactGroup = item as ContactGroup;
groupItemIds.Add(item.Id);//Using to send an email by item id, can classify by DisplayName etc..
}
}

Sending bulk emails in c # .net windows application

My project is to send at least 100 mails an hour.
I have used for loop to retrieve emails from database and send email one by one.
But When I googled i find out that it will get time out after some time.So What is the method to use to hold the mail sending for a while and then restart the loop from hold position.Also,if the sending failed i should resend it.Should I use timer?
Please provide me any idea to complete this.
My sample code,
List<string> list = new List<string>();
String dbValues;
foreach (DataRow row in globalClass1.dtgrid.Rows)
{
//String From DataBase(dbValues)
dbValues = row["email"].ToString();
list.Add(dbValues);
}
using (System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient(mailserver, port))
{
client.Credentials = new System.Net.NetworkCredential(emailfrom, password);
client.EnableSsl = true;
MailMessage msg1 = new MailMessage();
foreach (string row in list)
{
if (row != null)
{
msg1=sendmail(row);
client.Send(msg1);
client.Dispose();
}
}}
Option 1
You can simply Add multiple recipients to To property of MailMessage:
var mail = new MailMessage();
mail.To.Add(new MailAddress("to#example.com"));
For example when you have a list that contains recipients, you can add theme all:
var mail = new MailMessage();
foreach (var item in list)
{
mail.To.Add(new MailAddress(item));
}
mail.From = new MailAddress("from#example.com");
mail.Subject = "Subject";
mail.Body = "Body";
client.Send(mail);
Option 2
If you don't want to set all addresses using To or Bcc you can can use a Task to send emails this way:
public void SendMails(List<string> list)
{
Task.Run(() =>
{
foreach (var item in list)
{
//Put all send mail codes here
//...
//mail.To.Add(new MailAddress(item));
//client.Send(mail);
}
});
}
Option 3
You can also use SendMailAsync to send mails.
Thanks to Panagiotis Kanavos to mention that this way is preferred instead of using Task.Run .
You should rather send them asynchronously using the pickup directory. Here is a good overview. http://weblogs.asp.net/gunnarpeipman/asp-net-using-pickup-directory-for-outgoing-e-mails
The SMTP server handles transient network connectivity issues, and retries periodically.

EWS - Determine if an e-mail is a reply or has been forwarded

I am using the Exchange Web Services Managed API 2.2 to monitor users inboxes and need to determine if an e-mail is a new item, a reply or a forwarded message.
I have seen various articles on SO such as how to notice if a mail is a forwarded mail? and Is there a way to determine if a email is a reply/response using ews c#? which both help in their specific cases but I still cannot work out how to distinguish between a reply and a forwarded item.
In the first article an extra 5 bytes is added each time (forward or reply) so I don't know what the last action was.
The second article suggests using the InReplyTo however when I examine the property for forwarded e-mails it contains the original senders e-mail address (not null).
I have seen other articles such as this or this that suggest using extended properties to examine the values in PR_ICON_INDEX, PR_LAST_VERB_EXECUTED and PR_LAST_VERB_EXECUTION_TIME.
My code looks as follows but never returns a value for lastVerbExecuted
var lastVerbExecutedProperty = new ExtendedPropertyDefinition(4225, MapiPropertyType.Integer);
var response = service.BindToItems(newMails, new PropertySet(BasePropertySet.IdOnly, lastVerbExecutedProperty));
var items = response.Select(itemResponse => itemResponse.Item);
foreach (var item in items)
{
object lastVerb;
if (item.TryGetProperty(lastVerbExecutedProperty, out lastVerb))
{
// do something
}
}
PR_ICON_INDEX, PR_LAST_VERB_EXECUTED and PR_LAST_VERB_EXECUTION_TIME would only work to tell you if the recipient has acted on a message in their Inbox. Eg if the user had replied or forwarded a message in their inbox then these properties get set on the message in their Inbox. On the message that was responded to or forwarded these properties would not be set. I would suggest you use the In-Reply-To Transport header which should be set on any message that is replied to or forwarded, this should contain the internet messageid of the message that was replied to or forwarded eg.
FindItemsResults<Item> fiRs = service.FindItems(WellKnownFolderName.Inbox, new ItemView(10));
PropertySet fiRsPropSet = new PropertySet(BasePropertySet.FirstClassProperties);
ExtendedPropertyDefinition PR_TRANSPORT_MESSAGE_HEADERS = new ExtendedPropertyDefinition(0x007D, MapiPropertyType.String);
fiRsPropSet.Add(PR_TRANSPORT_MESSAGE_HEADERS);
service.LoadPropertiesForItems(fiRs.Items, fiRsPropSet);
foreach (Item itItem in fiRs)
{
Object TransportHeaderValue = null;
if(itItem.TryGetProperty(PR_TRANSPORT_MESSAGE_HEADERS,out TransportHeaderValue)) {
string[] stringSeparators = new string[] { "\r\n" };
String[] taArray = TransportHeaderValue.ToString().Split(stringSeparators, StringSplitOptions.None);
for (Int32 txCount = 0; txCount < taArray.Length; txCount++)
{
if (taArray[txCount].Length > 12)
{
if (taArray[txCount].Substring(0, 12).ToLower() == "in-reply-to:")
{
String OriginalId = taArray[txCount].Substring(13);
Console.WriteLine(OriginalId);
}
}
}
}
}
Apart from the Subject prefix that was discussed in the other link I don't know of any other proprieties that will differentiate between a reply or forward.
Cheers
Glen
The best way to rely is on the ResponeCode of Extended properties
Refer below scripts
private static int IsForwardOrReplyMail(ExchangeService service, EmailMessage messageToCheck)
{
try
{
// Create extended property definitions for PidTagLastVerbExecuted and PidTagLastVerbExecutionTime.
ExtendedPropertyDefinition PidTagLastVerbExecuted = new ExtendedPropertyDefinition(0x1081, MapiPropertyType.Integer);
ExtendedPropertyDefinition PidTagLastVerbExecutionTime = new ExtendedPropertyDefinition(0x1082, MapiPropertyType.SystemTime);
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.Subject, PidTagLastVerbExecutionTime, PidTagLastVerbExecuted);
messageToCheck = EmailMessage.Bind(service, messageToCheck.Id, propSet);
// Determine the last verb executed on the message and display output.
object responseType;
messageToCheck.TryGetProperty(PidTagLastVerbExecuted, out responseType);
if (responseType != null && ((Int32)responseType) == 104)
{
//FORWARD
return 104;
}
else if (responseType != null && ((Int32)responseType) == 102)
{
//REPLY
return 102;
}
}
catch (Exception)
{
return 0;
//throw new NotImplementedException();
}
}
To determine if it was a reply to a email, you can use the EmailMessage objects InReplyTo property, e.g:
EmailMessage mail = ((EmailMessage)Item.Bind(service, new ItemId(UniqueId)));
if (mail.InReplyTo == null)
return;
else
..your code

Using Mailkit to save attachments using IMAP

I have a need to find a particular email on a Google IMAP server and then save the attachments from the email. I think I have it all figured out except for the part of determining what the file name is of the attachment.
Below is my code so far, I am hoping that someone can point me in the right direction to determine the file name.
I have Googled and SO'd but have not been able to find something using the attachment approach.
internal class MailKitHelper
{
private void SaveAttachementsForMessage(string aMessageId)
{
ImapClient imapClient = new ImapClient();
imapClient.Connect("imap.google.com", 993, SecureSocketOptions.Auto);
imapClient.Authenticate("xxxx", "xxxx");
HeaderSearchQuery searchCondition = SearchQuery.HeaderContains("Message-Id", aMessageId);
imapClient.Inbox.Open(FolderAccess.ReadOnly);
IList<UniqueId> ids = imapClient.Inbox.Search(searchCondition);
foreach (UniqueId uniqueId in ids)
{
MimeMessage message = imapClient.Inbox.GetMessage(uniqueId);
foreach (MimeEntity attachment in message.Attachments)
{
attachment.WriteTo("WhatIsTheFileName"); //How do I determine the file name
}
}
}
}
And the winner is.....
attachment.ContentDisposition.FileName

Categories