We have the below code to read the attachments using EWS.
FindItemsResults<Item> foundItems = service.FindItems(FolderId, new ItemView(1000));
var orderItems = from list in foundItems
orderby list.DateTimeReceived
select list;
foreach (EmailMessage item in orderItems)
{
item.Load();//SARANYA
EmailMessage foundEmail = (EmailMessage)item;
EmailMessage message = EmailMessage.Bind(service, new ItemId(item.Id.ToString()), new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.Attachments, ItemSchema.Body));
if (message.Attachments.Count > 0)
{
FileAttachment[] attachments = null;
attachments = new FileAttachment[message.Attachments.Count];
foreach (Attachment attachment in message.Attachments)
{
try
{
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
// System.Threading.Thread.Sleep(2000);
fileAttachment.Load();
byte[] FolloupMailFileAttachmentContentBytes = fileAttachment.Content;
bool isScreenshot = false;
string ScreenfileName = "";
for (int i = 0; i < imgSrcs.Count; i++)
{
if (imgSrcs[i].ToString() == fileAttachment.Name.ToString())
{
isScreenshot = true;
if (!imgSrcs[i].ToString().Contains(".png"))
ScreenfileName = "cid:" + imgSrcs[i].ToString() + ".png";
else
ScreenfileName = "cid:" + imgSrcs[i].ToString();
break;
}
}
if (FolloupMailFileAttachmentContentBytes != null)
{
if (isScreenshot && RemoveSuccess == 1)
{
InsertMailItemAttachment(ScreenfileName, FolloupMailFileAttachmentContentBytes, caseid);
}
else
InsertMailItemAttachment(fileAttachment.Name.ToString(), FolloupMailFileAttachmentContentBytes, caseid);
}
}
else if (attachment is ItemAttachment)
{
item.Move(unreadmailFolder.Id);
}
}
catch (Exception exe)
{
if (!ReadMoved)
{
item.Move(readmailFolder.Id);
ReadMoved = true;
}
logfile.HandleError(exe, "Attachment Exception \n\nEmailbox - " + EMailBox + "\n\nEmail Subject - " + strSubject + " \n - Could not load the attachment (" + attachment.Name.ToString() + ")");
}
}
}
}
Above code is working when I provide thread.sleep() before fileattachment.load(). when thread.sleep is removed, I get the below exception.
Error Source : Microsoft.Exchange.WebServices
Target Site : Void InternalThrowIfNecessary()
System Message : The specified object was not found in the store.
Stack Trace : at Microsoft.Exchange.WebServices.Data.ServiceResponse.InternalThrowIfNecessary()
at Microsoft.Exchange.WebServices.Data.ServiceResponse.ThrowIfNecessary()
at Microsoft.Exchange.WebServices.Data.MultiResponseServiceRequest`1.Execute()
at Microsoft.Exchange.WebServices.Data.ExchangeService.InternalGetAttachments(IEnumerable`1 attachments, Nullable`1 bodyType, IEnumerable`1 additionalProperties, ServiceErrorHandling errorHandling)
at Microsoft.Exchange.WebServices.Data.ExchangeService.GetAttachment(Attachment attachment, Nullable`1 bodyType, IEnumerable`1 additionalProperties)
at Microsoft.Exchange.WebServices.Data.Attachment.InternalLoad(Nullable`1 bodyType, IEnumerable`1 additionalProperties)
at Microsoft.Exchange.WebServices.Data.Attachment.Load()
at EMT_Office365_MailFetch_Scheduler.Program.FindEmail(Object threadState) in
Experts, Please provide your valuable inputs
Your logic doesn't look correct eg
item.Move(unreadmailFolder.Id);
Should not be inside the Foreach loop if you want to move the message at the end just use a Flag and process it once you have finished processing the attachments(you logic doesn't work if you have two ItemAttachment this would execute twice). The reason sleep is working is mostly likely an Aysnc operation is completing once you have executed the move. Thats why this should be outside of the foreach attachment loop
Related
I have a mail containing only a signature as an image and an attachment like the screenshot below.
I save this email as C:\mail.msg, I try then to read it by the code below:
var oApp = new Microsoft.Office.Interop.Outlook.Application();
MailItem outlookMsg = (Microsoft.Office.Interop.Outlook.MailItem)oApp.CreateItemFromTemplate(#"C:\mail.msg");
//there are 2 attachments inside
foreach(var att in outlookMsg.Attachments)
{
att.SaveAsFile($#"C:\{att.FileName}");
}
The problem
There are 2 attachments inside the MailItem named :
-empty.xlsx
-lot4.xlsx
If I change the extension of lot4.xlsx to lot4.png, it can be opened as the image in the signature.
Someone has seen this strange situation when an attachment is added with name incorrect?
You could download attachments using the below code:
private void ThisApplication_NewMail()
{
Outlook.MAPIFolder inBox = this.Application.ActiveExplorer()
.Session.GetDefaultFolder(Outlook
.OlDefaultFolders.olFolderInbox);
Outlook.Items inBoxItems = inBox.Items;
Outlook.MailItem newEmail = null;
inBoxItems = inBoxItems.Restrict("[Unread] = true");
try
{
foreach (object collectionItem in inBoxItems)
{
newEmail = collectionItem as Outlook.MailItem;
if (newEmail != null)
{
if (newEmail.Attachments.Count > 0)
{
for (int i = 1; i <= newEmail
.Attachments.Count; i++)
{
newEmail.Attachments[i].SaveAsFile
(#"C:\TestFileSave\" +
newEmail.Attachments[i].FileName);
}
}
}
}
}
catch (Exception ex)
{
string errorInfo = (string)ex.Message
.Substring(0, 11);
if (errorInfo == "Cannot save")
{
MessageBox.Show(#"Create Folder C:\TestFileSave");
}
}
}
For more information, please refer to this link:
How to: Programmatically save attachments from Outlook email items
With Microsoft EWS, its very easy to do:
reference: http://johnlabtest.blogspot.com/2014/01/save-attachments-from-exchange-mail-box.html
static void Main(string[] args)
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Credentials = new WebCredentials("user1#contoso.com", "password");
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.AutodiscoverUrl("user1#contoso.com", RedirectionUrlValidationCallback);
var messages = new List<EmailMessage>();
// only get unread emails
SearchFilter folderSearchFilter = new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false);
// we just need the id in our results
var itemView = new ItemView(10) {PropertySet = new PropertySet(BasePropertySet.IdOnly)};
FindItemsResults<Item> findResults = service.FindItems(folder.Id, folderSearchFilter, itemView);
foreach (Item item in findResults.Items.Where(i => i is EmailMessage))
{
EmailMessage message = EmailMessage.Bind(service, item.Id, new PropertySet(BasePropertySet.IdOnly, ItemSchema.Attachments, ItemSchema.HasAttachments));
messages.Add(message);
}
// loop through messages and call processemail here.
}
public static void ProcessEmail(EmailMessage message)
{
string saveDir = ConfigurationManager.AppSettings["AttachmentSaveDirectory"];
if (message.HasAttachments)
{
foreach (Attachment attachment in message.Attachments.Where(a=> a is FileAttachment))
{
FileAttachment fileAttachment = attachment as FileAttachment;
fileAttachment.Load(); // populate the content property of the attachment
using (FileStream fs = new FileStream(saveDir + attachment.Name, FileMode.Create))
{
using (BinaryWriter w = new BinaryWriter(fs))
{
w.Write(fileAttachment.Content);
}
}
}
}
message.IsRead = true;
message.Update(ConflictResolutionMode.AutoResolve); // push changes back to server
}
private static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
// The default for the validation callback is to reject the URL.
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
// Validate the contents of the redirection URL. In this simple validation
// callback, the redirection URL is considered valid if it is using HTTPS
// to encrypt the authentication credentials.
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
I am developing a c# add-in for Outlook 2016. In some procedures I need to remove the mail item category and user properties. I am trying to do this by removing properties from inbox/sent folder simultaneously. For this I start 2 new tasks:
Task.Factory.StartNew(() => RunRemovingExistingVisualIndicationFromInboxFolder(), GlobalEnvironmentMethods.removeExistingVisualIndicationFromInboxFolderCancellationToken.Token);
Task.Factory.StartNew(() => RunRemovingExistingVisualIndicationFromSentFolder(), GlobalEnvironmentMethods.removeExistingVisualIndicationFromInboxFolderCancellationToken.Token);
In my code below, is the function which removes these properties (for example, I attach only processing mail items in my Inbox folder. Note: the same code is used for my Sent folder. I only changed the Outlook folder to use the "Sent" folder.)
public static void RunRemovingExistingVisualIndicationFromInboxFolder()
{
NLogMethods.GetInstance().WriteInfoLog("[ADDITIONALVISUALINDICATIONSETTINGSFORM -> RUNREMOVEEXISTINGVISUALINDICATION()]: Processing " + "\"" + "Inbox" + "\"" + " folder started.");
Outlook.Items folderItemsInbox = null;
folderItemsInbox = OutlookMethods.currentOAppNameSpace.Stores[JSONMethods.ReadAddInSetting().AddInPreferredMailBoxStoreName].GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).Items;
if (folderItemsInbox.Count > 0)
{
for (int i = 1; i <= folderItemsInbox.Count; i++)
{
totalProcessedInboxMailItems++;
if (GlobalEnvironmentMethods.removeExistingVisualIndicationFromInboxFolderCancellationToken.IsCancellationRequested)
{
GlobalEnvironmentMethods.globalProcessingRemovingVisualIndicationTaskState = false;
GlobalEnvironmentMethods.removeExistingVisualIndicationFromInboxFolderCancellationToken.Dispose();
GlobalEnvironmentMethods.removeExistingVisualIndicationFromInboxFolderCancellationToken = null;
GlobalEnvironmentMethods.ServiceProcedures.ReleaseComObject(new[] { folderItemsInbox });
totalProcessedInboxMailItems = 0;
NLogMethods.GetInstance().WriteWarnLog("[ADDITIONALVISUALINDICATIONSETTINGSFORM -> RUNREMOVEEXISTINGVISUALINDICATION()]: The task was cancelled by user.");
return;
}
else
{
Outlook.MailItem mailItemObjectInbox = null;
mailItemObjectInbox = folderItemsInbox[i] as Outlook.MailItem;
if (mailItemObjectInbox != null)
{
if (mailItemObjectInbox.Class == Outlook.OlObjectClass.olMail)
{
bool mailItemChanged = false;
if (mailItemObjectInbox.Categories != null)
{
if (mailItemObjectInbox.Categories.Contains(AddInEnvironmentMethods.CRM_CATEGORY_NAME.ToLower()) || mailItemObjectInbox.Categories.Contains(AddInEnvironmentMethods.CRM_CATEGORY_NAME.ToUpper()))
{
//When mail item has many categories, our need remove from string only our "CRM" category, other categories, include char "," will be applied correctly by Outlook automatically;
//i.e. if mail item has 3 cat.: Green category, CRM, Yellow category -> after removing "CRM" cat. category text was: Green category, , Yellow category, but don't worry, Outlook will apply this string absolutely correctly;
//Note: Mail item categories is case sensitive;
mailItemChanged = true;
if (mailItemObjectInbox.Categories.Contains(AddInEnvironmentMethods.CRM_CATEGORY_NAME.ToLower()))
{
mailItemObjectInbox.Categories = mailItemObjectInbox.Categories.Remove(mailItemObjectInbox.Categories.IndexOf(AddInEnvironmentMethods.CRM_CATEGORY_NAME.ToLower()), AddInEnvironmentMethods.CRM_CATEGORY_NAME.Length);
}
else if (mailItemObjectInbox.Categories.Contains(AddInEnvironmentMethods.CRM_CATEGORY_NAME.ToUpper()))
{
mailItemObjectInbox.Categories = mailItemObjectInbox.Categories.Remove(mailItemObjectInbox.Categories.IndexOf(AddInEnvironmentMethods.CRM_CATEGORY_NAME.ToUpper()), AddInEnvironmentMethods.CRM_CATEGORY_NAME.Length);
}
}
}
if (mailItemObjectInbox.UserProperties.Find(AddInEnvironmentMethods.CRM_COLUMN_NAME) != null)
{
mailItemChanged = true;
mailItemObjectInbox.UserProperties.Find(AddInEnvironmentMethods.CRM_COLUMN_NAME).Delete();
}
if (mailItemChanged)
{
mailItemObjectInbox.Save();
}
GlobalEnvironmentMethods.ServiceProcedures.ReleaseComObject(new[] { mailItemObjectInbox });
}
else
{
GlobalEnvironmentMethods.ServiceProcedures.ReleaseComObject(new[] { mailItemObjectInbox });
}
}
}
}
}
else
{
GlobalEnvironmentMethods.ServiceProcedures.ReleaseComObject(new[] { folderItemsInbox });
}
GlobalEnvironmentMethods.globalProcessingRemovingVisualIndicationTaskState = false;
GlobalEnvironmentMethods.removeExistingVisualIndicationFromInboxFolderCancellationToken.Dispose();
GlobalEnvironmentMethods.removeExistingVisualIndicationFromInboxFolderCancellationToken = null;
NLogMethods.GetInstance().WriteInfoLog("[ADDITIONALVISUALINDICATIONSETTINGSFORM -> RUNREMOVEEXISTINGVISUALINDICATION()]: Processing " + "\"" + "Inbox" + "\"" + " folder completed.");
}
The count of processing mail items in my Inbox folder = 988 items.
But, sometimes this function catches an exception "Out of memory".
I don't understand why this occurs...
Note: Exception occurred on this line of code:
if (mailItemObjectInbox.Categories != null) //Out of memory ex...
What am I doing incorrect? Thanks
Referring to the answer mentioned in the post:
Reading Outlook Mail with C#
This code works well for a single account, but the issue with the current code is that it reads the email of the default id which was set as the first one in the outlook app.
For example, if "abcxyz#outlook.com" is set as the first account and "decxyz#outlook.com" is set as the second one, then it reads the inbox of only the first id, i.e., "abcxyz#outlook.com". I tried doing some modifications in the code but it did not work. Below is my code:
public static void OutLookMailStart(string EmailID, string password)
{
Microsoft.Office.Interop.Outlook.Application app = null;
Microsoft.Office.Interop.Outlook._NameSpace ns = null;
Microsoft.Office.Interop.Outlook.PostItem item = null;
Microsoft.Office.Interop.Outlook.MAPIFolder inboxFolder = null;
Microsoft.Office.Interop.Outlook.MAPIFolder subFolder = null;
Microsoft.Office.Interop.Outlook.MailItem mailItem = null;
try
{
app = new Microsoft.Office.Interop.Outlook.Application();
ns = app.GetNamespace("MAPI");
ns.Logon(EmailID, password, false, true);
inboxFolder = ns.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
foreach (Object mail in inboxFolder.Items)
{
if ((mail as MailItem) != null && (mail as MailItem).UnRead == true)
{
// Email Subject
string Subject = (mail as MailItem).Subject.ToString();
if (Subject.Contains(FileDomain))
{
// Email Body
var ReplyText = ExtractReply(((mail as MailItem).Body.ToString()), FromTrimName);
}
// (mail as MailItem).UnRead = false;
(mail as MailItem).Save();
}
}
}
catch (System.Exception ex)
{
throw ex;
}
finally
{
ns.Logoff();
inboxFolder = null;
subFolder = null;
mailItem = null;
app = null;
}}
Any sort of help will be appreciated.
public static void OutLookMailStart(string EmailID, string password)
{
Microsoft.Office.Interop.Outlook.Application app = null;
Microsoft.Office.Interop.Outlook._NameSpace ns = null;
Microsoft.Office.Interop.Outlook.PostItem item = null;
Microsoft.Office.Interop.Outlook.MAPIFolder inboxFolder = null;
Microsoft.Office.Interop.Outlook.MAPIFolder subFolder = null;
Microsoft.Office.Interop.Outlook.MailItem mailItem = null;
try
{
app = new Microsoft.Office.Interop.Outlook.Application();
ns = app.GetNamespace("MAPI");
ns.Logon(EmailID, password, true, true);
inboxFolder = ns.Folders[EmailID].Folders[2];
foreach (Microsoft.Office.Interop.Outlook.MailItem mailItemm in inboxFolder.Items)
{
if (mailItemm.UnRead) // I only process the mail if unread
{
// Email Subject
Console.WriteLine("Subject : {0}", mailItemm.Subject);
string Subject = mailItemm.Subject;
if (!string.IsNullOrEmpty(Subject) && !string.IsNullOrWhiteSpace(Subject))
{
if (Subject.Contains(FileDomain))
{
var SenderName = mailItemm.Sender.Name;
//Email Body
Console.WriteLine("Accounts: {0}", mailItemm.Body);
// Read All Attachements
var attachments = (mailItemm as MailItem).Attachments;
if (attachments != null && attachments.Count > 0)
{
for (int i = 1; i <= attachments.Count; i++)
{
attachments[i].SaveAsFile(tempFolderPath + (mailItemm as MailItem).Attachments[i].FileName);
}
}
}
}
}
}
}
catch (System.Exception ex)
{
throw ex;
}
finally
{
ns.Logoff();
inboxFolder = null;
subFolder = null;
mailItem = null;
app = null;
}
}
Using ExchangeService service
public static void Cloud_OutLookMailStart(string EmailID, string password, string StoreFilePath)
{
try
{
LogHelper.LogMessage("<----- Cloud_OutLookMailStart Start ----->");
DistributionReplyEntity ObjDistributionReplyEntity = new DistributionReplyEntity();
ObjDistributionReplyEntity.OutLookEmailID = EmailID;
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
service.Credentials = new WebCredentials(EmailID, password);
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
//service.Url = new Uri("https://IP/EWS/Exchange.asmx");
service.AutodiscoverUrl(EmailID, RedirectionUrlValidationCallback);
Microsoft.Exchange.WebServices.Data.Folder inbox = Microsoft.Exchange.WebServices.Data.Folder.Bind(service, WellKnownFolderName.Inbox);
var items = service.FindItems(
//Find Mails from Inbox of the given Mailbox
new FolderId(WellKnownFolderName.Inbox, new Mailbox(EmailID)),
//Filter criterion
// new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter[] {
// new SearchFilter.ContainsSubstring(ItemSchema.Subject, ConfigurationManager.AppSettings["ValidEmailIdentifier"].ToString()),
new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false),
// }),
//View Size as 15
new ItemView(50));
Console.WriteLine("Email {0}, unread Total Count{1}", EmailID, items.Count());
foreach (Item item in items)
{
EmailMessage email = EmailMessage.Bind(service, new ItemId(item.Id.UniqueId.ToString()));
if (!string.IsNullOrEmpty(email.Subject) && !string.IsNullOrWhiteSpace(email.Subject))
{
var subject = email.Subject.ToString();
String[] arr = subject.Split(' ');
String firstWord = arr[0];
if (firstWord != "Undeliverable:")
{
//PROCESS EMAIL MESSAGE
Console.WriteLine("Subject :{0}", email.Subject);
// TO
if (email.ToRecipients.Count > 0)
{
var propertySet = new PropertySet(ItemSchema.UniqueBody);
EmailMessage email2 = EmailMessage.Bind(service, email.Id, propertySet);
EmailMessage str = (EmailMessage)email2;
string str1 = str.UniqueBody.Text.ToString();
var EmailBody = ExtractReply(str1, "");
// string ReceiverEmail = email.ReceivedBy != null?email.ReceivedBy.Address:"" ;
// Email Body
// var subjectEmail = ExtractReply(email.Body.ToString(), email.ReceivedBy.Address);
Console.WriteLine("Body {0}", EmailBody.ToString()); // Body
ObjDistributionReplyEntity.EmailBody = EmailBody;
string maltipleTo = string.Empty;
foreach (var toemailid in email.ToRecipients)
{
if (string.IsNullOrEmpty(maltipleTo))
{
maltipleTo = toemailid.Address.ToString();
}
else
{
maltipleTo += ";" + toemailid.Address.ToString();
}
}
Console.WriteLine("TO {0}", maltipleTo.ToString()); // TO
ObjDistributionReplyEntity.ReplyTO = maltipleTo.ToString();
}
// CC
if (email.CcRecipients.Count > 0)
{
string maltipleCC = string.Empty;
foreach (var ccemailid in email.CcRecipients)
{
if (string.IsNullOrEmpty(maltipleCC))
{
maltipleCC = ccemailid.Address.ToString();
}
else
{
maltipleCC += ";" + ccemailid.Address.ToString();
}
}
Console.WriteLine("CC {0}", maltipleCC.ToString());
ObjDistributionReplyEntity.ReplyCC = maltipleCC.ToString();
}
// Form
if (email.Sender.Address != "")
{
ObjDistributionReplyEntity.ReplyForm = email.Sender.Address;
}
Console.WriteLine("Subject {0}", email.Subject.ToString()); // Subject
ObjDistributionReplyEntity.Subject = email.Subject.ToString();
ObjDistributionReplyEntity.TransactionsID = 0;
ObjDistributionReplyEntity.IsProjectRelated = 0;
string Subject = email.Subject;
ObjDistributionReplyEntity.ReceivedTime = email.DateTimeReceived;
var getSharePointFileUrl = GetAttachmentsFromEmail(service, item.Id, StoreFilePath, ObjDistributionReplyEntity.TransactionsID);
email.IsRead = true;
email.Update(ConflictResolutionMode.AlwaysOverwrite);
}
}
}
LogHelper.LogMessage("<----- Cloud_OutLookMailStart Start ----->");
}
catch (Exception ex)
{
LogHelper.LogError("OutLookMailStart -> Cloud_OutLookMailStart Exception");
LogHelper.LogError("Exception Message :" + ex.Message);
if (ex.InnerException != null)
{
LogHelper.LogError("Exception InnerException :" + ex.InnerException);
}
LogHelper.LogError("Exception StackTrace :" + ex.StackTrace);
LogHelper.LogError("OutLookMailStart -> Cloud_OutLookMailStart Exception");
}
}
public static string GetAttachmentsFromEmail(ExchangeService service, ItemId itemId, string StoreFilePath, Int64 TransactionsID)
{
try
{
LogHelper.LogMessage("<----- GetAttachmentsFromEmail Start ----->");
// Bind to an existing message item and retrieve the attachments collection.
// This method results in an GetItem call to EWS.
EmailMessage message = EmailMessage.Bind(service, itemId, new PropertySet(ItemSchema.Attachments));
List<ResponseMessage> ObjResponseMessage = new List<ResponseMessage>();
// Iterate through the attachments collection and load each attachment.
foreach (Attachment attachment in message.Attachments)
{
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
// Load the attachment into a file.
// This call results in a GetAttachment call to EWS.
fileAttachment.Load(StoreFilePath + fileAttachment.Name);
string FileName = fileAttachment.Name;
LogHelper.LogMessage("OutLookMailStart In attachments File Name :" + FileName );
Console.WriteLine("File attachment name: " + fileAttachment.Name);
}
else // Attachment is an item attachment.
{
ItemAttachment itemAttachment = attachment as ItemAttachment;
// Load attachment into memory and write out the subject.
// This does not save the file like it does with a file attachment.
// This call results in a GetAttachment call to EWS.
itemAttachment.Load();
Console.WriteLine("Item attachment name: " + itemAttachment.Name);
}
}
}
catch (Exception ex)
{
LogHelper.LogError("OutLookMailStart -> GetAttachmentsFromEmail Exception");
LogHelper.LogError("Exception Message :" + ex.Message);
if (ex.InnerException != null)
{
LogHelper.LogError("Exception InnerException :" + ex.InnerException);
}
LogHelper.LogError("Exception StackTrace :" + ex.StackTrace);
LogHelper.LogError("OutLookMailStart -> GetAttachmentsFromEmail Exception"); ;
}
LogHelper.LogMessage("<----- GetAttachmentsFromEmail End ----->");
}
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;
}
I have a sample application which upload a file of size 26 MB to Amazon Glacier using AWS SDK for .NET High-Level API. the code works fine without threading but with thread pool its fails at the below line
client.UploadMultipartPart(uploadMPUrequest);
saying error Message:
The request was aborted: The request was canceled.
Stack Trace: at Amazon.Runtime.AmazonWebServiceClient.handleHttpWebErrorResponse(AsyncResult asyncResult, WebException we)
at Amazon.Runtime.AmazonWebServiceClient.getRequestStreamCallback(IAsyncResult result)
at Amazon.Runtime.AmazonWebServiceClient.InvokeConfiguredRequest(AsyncResult asyncResult)
at Amazon.Runtime.AmazonWebServiceClient.InvokeHelper(AsyncResult asyncResult)
at Amazon.Runtime.AmazonWebServiceClient.Invoke(AsyncResult asyncResult)
at Amazon.Glacier.AmazonGlacierClient.invokeUploadMultipartPart(UploadMultipartPartRequest uploadMultipartPartRequest, AsyncCallback callback, Object state, Boolean synchronized)
at Amazon.Glacier.AmazonGlacierClient.UploadMultipartPart(UploadMultipartPartRequest uploadMultipartPartRequest)
Note: I am uploading the data in multi part
please find the below link for my sample code:
www.page-monitor.com/Downloads/ArchiveUploadMPU.cs
Is there any sample code for parallel upload of archive?
Thanks and Regards,
Haseena
I believe there is a race condition in the code. I am working on the same functionality. I'd be happy to share code with you. If you fixed the code you posted I'd appreciate a link to it.
Best Regards,
Bruce
Here is the sample code that works fine with threading. ChunkDetails is a custom library for passing the accessID, bucketname, offset detail, etc. I am also using ThrottledStream.
internal bool UploadUsingHighLevelAPI(String FilePath, ChunkDetails ObjMetaData,
S3Operations.UploadType uploadType,
Stream inputStream)
{
String METHOD_NAME = "UploadUsingHighLevelAPI";
String keyName;
String existingBucketName;
TransferUtilityUploadRequest fileTransferUtilityRequest = null;
int RetryTimes = 3;
ThrottledStream throttleStreamObj = null;
long bps = ThrottledStream.Infinite;
try
{
keyName = ObjMetaData.KeyName;
existingBucketName = ObjMetaData.BucketName;
TransferUtility fileTransferUtility = new
TransferUtility(ObjMetaData.AccessKeyID, ObjMetaData.SecretAccessKey);
FileInfo fin = new FileInfo(FilePath);
//streamObj = new FileStream(FilePath, FileMode.Open);
bps = (long)(1024 * ObjMetaData.MaxAvailSpeed * ((double)ObjMetaData.Bandwidth / 100.0));
throttleStreamObj = new ThrottledStream(ObjMetaData.FileStream, bps);
System.Collections.Specialized.NameValueCollection metaInfo = new System.Collections.Specialized.NameValueCollection();
if (ObjMetaData.MetaInfo != null)
{
foreach (DictionaryEntry kvp in ObjMetaData.MetaInfo)
{
metaInfo.Add(kvp.Key.ToString(), kvp.Value.ToString());
}
}
long OffDiff = ObjMetaData.EndOffset - ObjMetaData.StartOffset;
long partSize;
if (fin.Length >= OffDiff)
{
partSize = OffDiff;
}
else
partSize = fin.Length;
if (uploadType == UploadType.File)
{
//fileTransferUtility.Upload(FilePath, existingBucketName, keyName);
fileTransferUtilityRequest =
new TransferUtilityUploadRequest()
.WithBucketName(existingBucketName)
//.WithFilePath(FilePath)
.WithStorageClass(S3StorageClass.ReducedRedundancy)
.WithMetadata(metaInfo)
.WithPartSize(partSize)
.WithKey(keyName)
.WithCannedACL(S3CannedACL.PublicRead)
.WithTimeout(Int32.MaxValue - 1)
.WithInputStream(throttleStreamObj) as TransferUtilityUploadRequest;
}
else if (uploadType == UploadType.Stream)
{
fileTransferUtilityRequest =
new TransferUtilityUploadRequest()
.WithBucketName(existingBucketName)
.WithStorageClass(S3StorageClass.ReducedRedundancy)
.WithMetadata(metaInfo)
.WithPartSize(partSize)
.WithKey(keyName)
.WithCannedACL(S3CannedACL.PublicRead)
.WithTimeout(Int32.MaxValue - 1)
.WithInputStream(throttleStreamObj) as TransferUtilityUploadRequest
;
}
for (int index = 1; index <= RetryTimes; index++)
{
try
{
// Upload part and add response to our list.
fileTransferUtility.Upload(fileTransferUtilityRequest);
Console.WriteLine(" ====== Upload Done =========");
if (eventChunkUploaded != null)
eventChunkUploaded(ObjMetaData);
break;
}
catch (Exception ex)
{
if (index == RetryTimes)
{
m_objLogFile.LogError(CLASS_NAME, METHOD_NAME + " - Attempt " +
index + Environment.NewLine + FilePath, ex);
if (eventChunkUploadError != null)
eventChunkUploadError(ObjMetaData, ex.Message);
}
}
}
}
catch (Exception ex)
{
m_objLogFile.LogError(CLASS_NAME, METHOD_NAME, ex);
return false;
}
finally
{
if (throttleStreamObj != null)
{
//inputStream1.Close();
throttleStreamObj = null;
}
}
return true;
}
Let me know if you face any issue.