i'm using Outlook Interop and C# to get some mail information to create an excel report. I have email items list from Sent Items folder and i want to get the email address who i sent the mail. I found the "To" property but only return the person name not the address.
Anyone can please help me to return the email addres from Outlook.MailItem object?
You can ask me if you need more information. Thanks!!!!
Here is my code where i am setting the properties:
foreach (object mail in mails)
//mails is a list from Sent Items folder
{
if (mail is Outlook.MailItem)
{
var item = (Outlook.MailItem)mail;
//i need the address in provider email
var providerEmail = someProperty(????);
var name = item.To;
var request= "Other Request";
var emailDate= item.ReceivedTime;
var status = "Closed";
var responseDate= item.CreationTime;
var reportObject = new ReportModel
{
Email = providerEmail ,
Name = name,
Solicitud = request,
EmailDate = emailDate,
Status = status,
ResponseDate = responseDate
};
}
}
MailItem has Recipients property, you can use it to obtain recipient of each type:
To
Cc
Bcc.
Use recipient.Type to recognize recipient type and recipient.Address to obtain its email address.
Example:
protected override void getRecepients(MailItem OLitem, StringBuilder toStringBuilder,
StringBuilder ccStringBuilder, StringBuilder bccStringBuilder)
{
try
{
var recipients = OLitem.Recipients;
string parent = string.Empty;
foreach (Microsoft.Office.Interop.Outlook.Recipient recipient in recipients)
{
switch (recipient.Type)
{
case (int)Microsoft.Office.Interop.Outlook.OlMailRecipientType.olTo:
toStringBuilder.Append(recipient.Address + ", ");
if (parent == string.Empty)
{
parent = recipient.Address;
}
break;
case (int)Microsoft.Office.Interop.Outlook.OlMailRecipientType.olCC:
ccStringBuilder.Append(recipient.Address + ", ");
break;
case (int)Microsoft.Office.Interop.Outlook.OlMailRecipientType.olBCC:
bccStringBuilder.Append(recipient.Address + ", ");
break;
default:
break;
}
}
}
catch (Exception ex)
{
// do something with error
}
}
Related
I need to move a mail from a list of 5 mails that a class reads. This mail already has been processed by a logical that I created and has met the conditional created. The problem is that it moves those 5 emails and some do not meet the conditions. If the mail that has fulfilled the condition manages to enter the data into the database then it must be moved to the processed mail folder otherwise it must be moved to the error folder.
This is the class that gets the emails
int bufferLength = 5;
int indiceMail = 0;
string from = "mail#gmail.com>";
do
{
emailList.getEmails(bufferLength);
while(indiceMail<emailList.emails.Count)
{
indiceMail++;
}
Console.WriteLine("Reading: {0}", emailList.emails.Count);
}while (emailList.MoreAvailable);
And this is the condition to move the mails
string bodyMail = emailList.emails[indiceMail].body;
match3 = Regex.Match(bodyMail, #"(?<=Status:) (\S+\b)");
statuscompare = match3.Value;
List<String> statusList = new List<string> { "i2", "i3", "i4", "i8" };
bool ex = false;
foreach (string item1 in statusList)
{
if (item1.Contains(statuscompare.Trim()))
{
ex = true;
if (item1.Contains("i4"))
{
bool moveEmail = false;
foreach (Email item in emailList.emails)
{
if (emailList.emails[indiceMail].body.Contains("i4"))
{
// if (item.body.Contains(item1))
//{
moveEmail = true;
emailList.moveMail(item.id, emailList.config.PathSuccess);
break;
// }
}
if (moveEmail)
{
continue;
}
}
}
}
}
This is part of a class to move the mails
public void moveMail(string emailId, string folderPath)
{
string folderId = getMailFolderId(folderPath);
EmailMessage message = EmailMessage.Bind(service, emailId);
message.Move(folderId);
}
Once you process an email with error, you set the flag 'emailbool' to false, which moves every other email to the PathSuccess. Not sure how emailbool actually serves any purpose other than making sure only one email from all goes to error path.
foreach (Email item in emailList.emails)
{
// This IF statement will either be true of false for ALL items.
if (!Cmmd.Parameters["p_retorno"].Value.ToString().Equals("0"))
{
emailList.moveMail(item.id, emailList.config.PathError);
}
else
{
emailList.moveMail(item.id, emailList.config.PathSuccess);
}
}
EDIT: For new code you posted, try this to move all emails that contain any string from statusList in its body.
// This will move all emails that have one or more statusList in their body
foreach (Email item in emailList.emails)
{
if (statusList.Where(x => item.body.Contains(x)).Count > 0)
{
emailList.moveMail(item.id, emailList.config.PathSuccess);
break; // This statement will stop processing of any other emails.
}
}
I want to send EMails with C# and the Microsoft.Office.Interop.Outlook library.
I am locked in, on my Outlook account with a#domain.com and got the rights on the exchange server to send mails from b#domain.com and c#domain.com.
I don't find any way to send a mail with B or C.
I got everything working for my user account which has the mail a#domain.com.
Now I can't find a way to get the account of b#domain.com and send a mail in the name of B.
My Question:
How do I get access to the other accounts?
That's the code I have:
using Outlook = Microsoft.Office.Interop.Outlook;
public static Outlook.Account GetAccountForEmailAddress(Outlook.Application application, string smtpAddress)
{
// Loop over the Accounts collection of the current Outlook session.
Outlook.Accounts accounts = application.Session.Accounts;
if (_IsDebug)
Console.WriteLine($"Anzahl Accounts: {accounts.Count}");
foreach (Outlook.Account account in accounts)
{
// When the e-mail address matches, return the account.
if (_IsDebug)
Console.WriteLine($"Account: {account.SmtpAddress}");
if (String.Compare(account.SmtpAddress, smtpAddress, true) == 0)
{
return account;
}
}
throw new System.Exception(string.Format("No Account with SmtpAddress: {0} exists!", smtpAddress));
}
static void SendEMail(string emailadress)
{
try
{
var outlookApplication = new Outlook.Application();
var outlookMailItem = (Outlook.MailItem)outlookApplication.CreateItem(Outlook.OlItemType.olMailItem);
outlookMailItem.SendUsingAccount = GetAccountForEmailAddress(outlookApplication, ConfigurationManager.AppSettings[SENDER]);
if (_IsDebug)
Console.WriteLine($"Absender: {outlookMailItem?.SendUsingAccount?.SmtpAddress}");
outlookMailItem.HTMLBody = ConfigurationManager.AppSettings[BODY];
if (_IsDebug)
Console.WriteLine($"Body: {outlookMailItem?.HTMLBody}");
var file = GetPDFFile();
if (_IsDebug)
Console.WriteLine($"File: {file?.Name}");
if (file == null)
{
Console.WriteLine("Keine Datei gefunden!");
return;
}
string attachementDisplayName = file.Name;
int attachementPosition = outlookMailItem.HTMLBody.Length + 1;
int attachementType = (int)Outlook.OlAttachmentType.olByValue;
if (_IsDebug)
Console.WriteLine($"Dateianhang: {file.FullName}");
Outlook.Attachment outlookAttachement = outlookMailItem.Attachments.Add(file.FullName, attachementType, attachementPosition, attachementDisplayName);
outlookMailItem.Subject = ConfigurationManager.AppSettings[SUBJECT];
Outlook.Recipients outlookRecipients = outlookMailItem.Recipients;
Outlook.Recipient outlookRecipient = outlookRecipients.Add(emailadress);
outlookRecipient.Resolve();
outlookMailItem.Send();
outlookRecipient = null;
outlookRecipients = null;
outlookMailItem = null;
outlookApplication = null;
if (_IsDebug)
Console.ReadLine();
}
catch (Exception)
{
throw;
}
}
You have to grant the owner of the sending mailbox Send As permissions on the mailboxes you want to send the emails from. Send on behalf of permissions will work but will say "A on behalf of B" as the sender.
This problem is happening for one of our customers and I have been unable to replicate on my side using the same version of Outlook. My customer and I are using Office 365 with Outlook 2016 installed. When he sends an email in our program via Outlook Redemption (a third party program used for Outlook integration), the mail gets stuck in his outbox.
If he double clicks the message (so it pops up in Outlook) he can hit the send button and it will sucessfuly send. If they use an old version of Outlook (2010) this is not a problem. I upgraded them to the the newest version of Outlook Redmeption at the time (released May 07, 2016), though it looks like they just came out with a new version a few days ago. I'll try that soon, but the changelog doesn't mention mail getting stuck in the Outbox.
I also noticed that the emails in his outbox have what appears to be the 'draft' symbol on them, while in my outbox they have a 'sending' symbol on them. This seems important, but I'm not sure what I can do about that.
Also, hitting Send/Receive All Folders does not help.
My code is below. Thank you for any assistance.
public static bool SendMessage(Recipients recipients, string[] addressListReplyTo, string subject, string body, string[] attachments, bool requestReadReceipt, Log log, bool isHtmlBody = false)
{
RDOSession session = null;
RDOMail mail;
RDOFolder folder;
bool result = true;
session = GetSessionAndLogon(log);
if (session == null)
return false;
folder = session.GetDefaultFolder(rdoDefaultFolders.olFolderOutbox);
mail = folder.Items.Add();
if (isHtmlBody)
mail.HTMLBody = body;
else
mail.Body = body;
mail.Subject = subject;
mail.ReadReceiptRequested = requestReadReceipt;
foreach (string attachment in attachments)
{
if (attachment != "")
mail.Attachments.Add(attachment);
}
foreach (string address in addressListReplyTo)
{
if (address != "")
mail.ReplyRecipients.Add(address);
}
foreach (string address in recipients.To)
{
if (address != "")
mail.Recipients.Add(address).Type = 1;
}
foreach (string address in recipients.Cc)
{
if (address != "")
mail.Recipients.Add(address).Type = 2;
}
foreach (string address in recipients.Bcc)
{
if (address != "")
mail.Recipients.Add(address).Type = 3;
}
foreach (RDORecipient recipient in mail.Recipients)
{
if (!OutlookMailEngine64.existsName(recipient.Name, session, log == null ? null : log))
result = false;
}
if (result)
{
try
{
mail.Send();
result = true;
}
catch (System.Runtime.InteropServices.COMException ex)
{
string message = "Error while sending email: " + ex.Message;
if (log != null)
log.Message(message);
if (OutlookMailEngine64.DiagnosticMode)
MessageBox.Show(message);
throw new EmailLibraryException(EmailLibraryException.ErrorType.InvalidRecipient, "One or more recipients are invalid (use OutlookMailEngine64.ValidateAddresses first)", ex);
}
}
if (session.LoggedOn)
session.Logoff();
return result;
}
Keep in mind that message submission is asynchronous, and it will nto be automatically triggered unless you are using the online Exchange store (where store and transport provider are tightly coupled).
You can force send/receive by calling Namespace.SendAndReceive in the Outlook Object Model.
Dmitry worked with me via email. The solution for me was to swap out RDO for the SafeMailItem object. Here is the updated version of my method so you can see the changes:
private static bool SendSafeMessage(Recipients recipients, string[] addressListReplyTo, string subject, string body, string[] attachments, bool requestReadReceipt, Log log, bool isHtmlBody = false)
{
//This method was added because sometimes messages were getting stuck in the Outlook Outbox and this seems to solve that
bool result = true;
Microsoft.Office.Interop.Outlook.Application application = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace namespaceMAPI = application.GetNamespace("MAPI");
namespaceMAPI.Logon();
RDOSession session = null;
session = GetSessionAndLogon(log); //TODO: I'm creating a 2nd session here which is wasteful
SafeMailItem safeMail = Redemption.RedemptionLoader.new_SafeMailItem();
Microsoft.Office.Interop.Outlook.MailItem outlookMailItem = (Microsoft.Office.Interop.Outlook.MailItem)application.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);
safeMail.Item = outlookMailItem;
if (isHtmlBody)
outlookMailItem.HTMLBody = body;
else
safeMail.Body = body;
outlookMailItem.Subject = subject;
outlookMailItem.ReadReceiptRequested = requestReadReceipt;
foreach (string attachment in attachments)
{
if (attachment != "")
safeMail.Attachments.Add(attachment);
}
foreach (string address in addressListReplyTo)
{
if (address != "")
safeMail.ReplyRecipients.Add(address);
}
foreach (string address in recipients.To)
{
if (address != "")
safeMail.Recipients.Add(address).Type = 1;
}
foreach (string address in recipients.Cc)
{
if (address != "")
safeMail.Recipients.Add(address).Type = 2;
}
foreach (string address in recipients.Bcc)
{
if (address != "")
safeMail.Recipients.Add(address).Type = 3;
}
foreach (Microsoft.Office.Interop.Outlook.Recipient recipient in outlookMailItem.Recipients)
{
if (!OutlookMailEngine64.existsName(recipient.Name, session, log == null ? null : log))
result = false;
}
if (result)
{
try
{
safeMail.Send();
result = true;
}
catch (System.Runtime.InteropServices.COMException ex)
{
string message = "Error while sending email: " + ex.Message;
if (log != null)
log.Message(message);
if (OutlookMailEngine64.DiagnosticMode)
MessageBox.Show(message);
throw new EmailLibraryException(EmailLibraryException.ErrorType.InvalidRecipient, "One or more recipients are invalid (use OutlookMailEngine64.ValidateAddresses first)", ex);
}
}
if (session.LoggedOn)
session.Logoff();
namespaceMAPI.Logoff();
return result;
}
The title sums it up. I need to get all the MessageId properties from an Imap folder without downloading the entire message.
...
IMailFolder inbox = imapClient.Inbox;
SearchQuery query = SearchQuery.All;
IList<UniqueId> idsList = inbox.Search(query);
foreach (var uid in idsList)
{
MimeMessage message = inbox.GetMessage(uid);//This gets the entire message
//but I only need the .MessageId, without getting the other parts
if (message != null)
{
string messageId = message.MessageId;
}
}
...
Try this instead:
var summaries = client.Inbox.Fetch (0, -1, MessageSummaryItems.Envelope);
foreach (var message in summaries) {
Console.WriteLine (message.Envelope.MessageId);
}
That should get you what you want.
I'm using MailSystem.NET and trying to delete a message from the server. The problem is the IndexOnServer property is 0, and I get the following error:
Command "store 0 +flags.silent (\Deleted)" failed : 121031084812790 BAD Error in IMAP command STORE: Invalid messageset
Here's my code:
Imap4Client client = new Imap4Client();
client.Connect(account.Server, account.Username, account.Password);
var inbox = client.SelectMailbox("Inbox");
MessageCollection messages = inbox.SearchParse("SINCE " + DateTime.Now.AddHours(-hours).ToString("dd-MMM-yyyy"));
foreach (Message newMessage in messages)
{
inbox.DeleteMessage(newMessage.IndexOnServer, true);
}
How do I get the correct index of the message so I can delete it?
Edit:
The problem with the suggestions using the standard 1-based loop is that the counter index won't be in sync with the message index, since in my case I'm searching to retrieve a specific subset of messages only (as I understand it).
Thank you.
You can try deleting by the UID which should be more reliable and unique to each message. This has worked well for me in the past.
Edit: Since deleting the message causes all the indexes to shift down by one, you can use two separate counters. One to keep track of when you have iterated through the entire box (messagesLeft) and the other will keep track of the current message index which will be decreased by 1 if a message is deleted (since it would move up one place in line).
Mailbox box = client.AllMailboxes["inbox"];
Fetch fetch = box.Fetch;
int messagesLeft = box.Count;
int msgIndex = 0;
while (messagesLeft > 0)
{
msgIndex++;
messagesLeft--;
Message email = fetch.MessageObject(msgIndex);
if (criteria)
{
box.UidDeleteMessage(fetch.Uid(msgIndex), true);
msgIndex--;
}
}
In response to your comment, here is a fuller example of how you can use the UID for deletion without being concerned with the numeric position / index.
class Email
{
int UID { get; set; }
DateTime Sent { get; set; }
public string Body { get; set; }
// put whichever properties you will need
}
List<Email> GetEmails(string mailbox);
{
Mailbox box = client.AllMailboxes[mailbox];
Fetch fetch = box.Fetch;
List<Email> list = new List<Email>();
for (int x = 1; x <= box.MessageCount; x++)
{
Message msg = fetch.MessageObject(x);
list.Add(new Email() { } // set properties from the msg object
}
return list;
}
void DeleteEmail(Email email, string mailbox)
{
Mailbox box = client.AllMailboxes[mailbox];
box.UidDeleteMessage(email.Uid, true);
}
static void Main()
{
List<Email> emails = GetEmails("inbox");
emails = emails.Where(email => email.Sent < DateTime.Now.AddHours(-hours))
foreach (Email email in emails)
DeleteEmail(email);
}
This is official example from documantation.
instead of inbox.search("all") change it to your search query, etc.
http://mailsystem.codeplex.com/discussions/269304
//action_id is the Message.MessageId of the email
//action_flag is the Gmail special folder to move to (Trash)
//copying to Trash removes the email from the inbox, but it can't be moved back once done, even from the web interface
public static void move_msg_to(string action_id, string action_flag)
{
Imap4Client imap = new Imap4Client();
imap.ConnectSsl("imap.gmail.com", 993);
imap.Login("heythatsme#gmail.com", "heythatsmypassword");
imap.Command("capability");
Mailbox inbox = imap.SelectMailbox("inbox");
int[] ids = inbox.Search("ALL");
if (ids.Length > 0)
{
Message msg = null;
for (var i = 0; i < ids.Length; i++)
{
msg = inbox.Fetch.MessageObject(ids[i]);
if (msg.MessageId == action_id)
{
imap.Command("copy " + ids[i].ToString() + " [Gmail]/" + action_flag);
break;
}
}
}
}
just add 1 to the message index.
foreach (Message newMessage in messages)
{
inbox.DeleteMessage(newMessage.IndexOnServer + 1, true);
}
Try deleting last message first then second last and then come to delete first message.
IF you delete and expunge have been set then message number changes.