System.Runtime.InteropServices.COMException (0x80030020): The operation failed

0

I'm trying to save a Outlook.MailItem to a folder using:

MailItem.SaveAs(path, Outlook.OlSaveAsType.olMSG)

This works fine most of the time. However, when there's about 20 emails hitting Outlook at once, for a few of the I get the following exception:

System.Runtime.InteropServices.COMException (0x80030020): The operation failed.
   at Microsoft.Office.Interop.Outlook._MailItem.SaveAs(String Path, Object Type)

I checked the code 0x80030020 which seems to mean "A share violation has occurred." However, I'm not sure what it means. In my application, I have the two below lines where the first one saves the email to a folder and the second method trying to POST that file to an API:

file = MailItemHelper.SaveMailItemToOFEFolder(mailItem);
bool isEmailSentByHttp = MailItemHelper.SendMailItemToOFEApi(_userid, file)

The path has the subject of the email which is cleaned to remove non-alpha-numeric characters by doing:

Regex nonAlphaNumericRgx = new Regex(@"\W|_");
subject = nonAlphaNumericRgx.Replace(mail.Subject, "_");
c#
office-interop
asked on Stack Overflow Dec 8, 2017 by kovac • edited Dec 8, 2017 by kovac

1 Answer

1

I guess I can't tell directly what is the problem, but I can try giving you some tips.

According to MS documentation, Outlook seems to be using the StgOpenStorage function, throwing the STG_E_SHAREVIOLATION error:

Access denied because another caller has the file open and locked.

That means that either Outlook is messing up (the user clicked on the "message" and outlooks locks the file, or something else) or maybe after changing the file name with your regex your string ends up to be the same of another file, while it is in the middle of writing the other.

How are you hooking up to outlook? Is your app using a new thread per mail arrived? You could add a log4net and log all operations in your code, like:

// receive and email and store subject name on var subject
log.Info($"E mail with subject '{subject}' arrived.");
// convert name and save on var newSubject
log.Info($"Mail will be saved as '{newSubject}'.");
// notify the beginning of the operation
log.Info("Calling MailItemHelper.SaveMailItemToOFEFolder.");
// notify the end of the operation
log.Info("Mail saved successfully.");
// notify Post in REST API
log.Info("Sending in MailItemHelper.SendMailItemToOFEApi");
// notify end of Post in REST API
log.Info("MailItemHelper.SendMailItemToOFEApi sent");

This will give a clear idea of how all mails are being retrieved and if there is some thread issues you can check which ones are finishing/starting first.

answered on Stack Overflow Dec 8, 2017 by rodrigogq

User contributions licensed under CC BY-SA 3.0