I have been working on an IMAP client to get emails from Gmail. My application worked fine until about an hour ago, when attachments stopped being retrieved.
The connection and messaging is being handled by imapX.
Connection is OKAY
Login is OKAY
Getting folders is OKAY
Getting messages is OKAY
At this point attachments.Count == 0. It was working earlier this afternoon so I wonder if I have been over testing and Google have blacklisted my computer for a while? Does anyone know if this is the case? - Been running perhaps once every 5-10 minutes, maybe more at times so this could be a plausible issue.
I have attempted to send a new email with a totally new file and it still does not see the attachment (but it is (always) seeing the messages themselves).
Can any anyone shine some light on this issue?
EDIT : Header includes the following tag {[X-MS-Has-Attach, yes]}
EDIT (code) :
private void PollMailFolders(object state)
{
try
{
if(_imapClient == null || !_imapClient.IsConnected)
_imapClient = new ImapClient(_config.Server, _config.Port, true);
if (_imapClient.Connection())
{
if(!_imapClient.IsLogined)
_imapClient.LogIn(_config.Username, _config.Password);
string dateSearch = string.Format(
"SINCE {0:d-MMM-yyyy}{1}", DateTime.Today.AddDays(-_config.HistoryOnStartupDays),
_isFirstTime ? "" : " UNSEEN");
_isFirstTime = false;
foreach (Folder folder in _imapClient.Folders["SSForecasts"].SubFolder)
{
var messages = _imapClient.Folders[folder.Name].Search(dateSearch, false);
foreach (Message m in messages)
{
m.Process();
foreach (var a in m.Attachments)
{
SendDataToParser(_encoding.GetString(a.FileData), folder.Name);
}
m.SetFlag(ImapFlags.SEEN);
}
}
}
}
catch(Exception e)
{
_diagnostics.Logger.ErrorFormat("Error in PollMailFolders: {0}", e);
}
}
I have produced a work around which allows me to get the attachment data. Not the solution I had in mind, though it does work.
Simple filename extension check followed by a conversion of the message data.
BTW: _encoding = Encoding.GetEncoding(1252);
if (bodyPart.ContentFilename.EndsWith(".csv"))
{
return _encoding.GetString(Convert.FromBase64String(bodyPart.ContentStream));
}
Related
I wrote a program using CSOM to upload documents to SharePoint and insert metadata to the properties. once a while(like every 3 months) the SharePoint server gets busy or we reset IIS or any other communication problem that it may have, we get "The operation has timed out" error on clientContext.ExecuteQuery(). To resolve the issue I wrote an extension method for ExecuteQuery to try every 10 seconds for 5 times to connect to the server and execute the query. My code works in the Dev and QA environment without any problem but in Prod, when it fails the first time with timeout error, in the second attempt, it only uploads the document but it doesn't update the properties and all the properties are empty in the library. It doesn't return any error as result of ExecteQuery() but It seems from the two requests in the batch witch are uploading the file and updating the properties, it just does uploading and I don't know what happens to the properties. It kinda removes that from the batch in the second attempt!
I used both upload methods docs.RootFolder.Files.Add and File.SaveBinaryDirect in different parts of my code but I copy just one of them here so you can see what I have in my code.
I appreciate your help.
public static void ExecuteSharePointQuery(ClientContext context)
{
int cnt = 0;
bool isExecute = false;
while (cnt < 5)
{
try
{
context.ExecuteQuery();
isExecute = true;
break;
}
catch (Exception ex)
{
cnt++;
Logger.Error(string.Format("Communication attempt with SharePoint failed. Attempt {0}", cnt));
Logger.Error(ex.Message);
Thread.Sleep(10000);
if (cnt == 5 && isExecute == false)
{
Logger.Error(string.Format("Couldn't execute the query in SharePoint."));
Logger.Error(ex.Message);
throw;
}
}
}
}
public static void UploadSPFileWithProperties(string siteURL, string listTitle, FieldMapper item)
{
Logger.Info(string.Format("Uploading to SharePoint: {0}", item.pdfPath));
using (ClientContext clientContext = new ClientContext(siteURL))
{
using (FileStream fs = new FileStream(item.pdfPath, FileMode.Open))
{
try
{
FileCreationInformation fileCreationInformation = new FileCreationInformation();
fileCreationInformation.ContentStream = fs;
fileCreationInformation.Url = Path.GetFileName(item.pdfPath);
fileCreationInformation.Overwrite = true;
List docs = clientContext.Web.Lists.GetByTitle(listTitle);
Microsoft.SharePoint.Client.File uploadFile = docs.RootFolder.Files.Add(fileCreationInformation);
uploadFile.CheckOut();
//Update the metadata
ListItem listItem = uploadFile.ListItemAllFields;
//Set field values on item
foreach (List<string> list in item.fieldMappings)
{
if (list[FieldMapper.SP_VALUE_INDEX] != null)
{
TrySet(ref listItem, list[FieldMapper.SP_FIELD_NAME_INDEX], (FieldType)Enum.Parse(typeof(FieldType), list[FieldMapper.SP_TYPE_INDEX]), list[FieldMapper.SP_VALUE_INDEX]);
}
}
listItem.Update();
uploadFile.CheckIn(string.Empty, CheckinType.OverwriteCheckIn);
SharePointUtilities.ExecuteSharePointQuery(clientContext);
}
catch (Exception ex)
{
}
}
}
}
There's too many possible reasons for me to really comment on a solution, especially considering it's only on the prod environment.
What I can say is that it's probably easiest to keep a reference to the last uploaded file. If your code fails then check if the last file has been uploaded correctly.
Side note: I'm not sure if this is relevant but if it's a large file you want to upload it in slices.
I am trying to solve a problem where I have some contact information given as Outlook's *.msg files. I want to parse these files using a script to extract the contact emails and names. I tried couple of solutions:
I tried using Aspose's email library but could not get to the contact details.
If I open the .msg file with Outlook and save the file as a .txt file, the resulting file is a simple text file with the contact information listed and this file I can parse with the IO libraries and extract the information out. However I over hundred of these .msg files. I am using .NET and can't figure out how to implement the "Save As" text which I was able to do manually.
Any suggestions on how to go about this?
Thanks
Suresh
Using Apose.Email API, we can extract the contact email information. You may try this on your end.I tired this and was able to extract those information
MapiMessage message = MapiMessage.FromFile(msgPath);
MapiPropertyCollection properties = message.NamedProperties;
foreach (KeyValuePair<long, MapiProperty> prop in properties)
{
if (((prop.Value).Descriptor).CanonicalName != null)
{
if (((prop.Value).Descriptor).CanonicalName == "PidLidEmail1DisplayName")
{
string email1displayName = prop.Value.ToString();
}
if (((prop.Value).Descriptor).CanonicalName == "PidLidEmail1EmailAddress")
{
string email1Address = prop.Value.ToString();
}
if (((prop.Value).Descriptor).CanonicalName == "PidLidInstantMessagingAddress")
{
string ADD = prop.Value.ToString();
}
}
RDOSession session = RedemptionLoader.new_RDOSession();
session.Logon();
RDOFolder folder = session.GetDefaultFolder(rdoDefaultFolders.olFolderContacts);
Console.WriteLine("Extracting contacts...");
foreach (RDOFolder subFolder in folder.Folders)
{
if (subFolder.Name == "CAS_Notifications")
{
foreach (var rdoItem in subFolder.Items)
{
RDOContactItem contactItem = rdoItem as RDOContactItem;
RDODistListItem distList = rdoItem as RDODistListItem;
if (distList != null)
{
Console.WriteLine("Distribution List");
foreach (RDOAddressEntry rdoAddressEntry in distList.OneOffMembers)
{
Console.WriteLine("Name: {0}; Email: {1}", rdoAddressEntry.Name, rdoAddressEntry.SMTPAddress);
}
}
else if (contactItem != null)
{
Console.WriteLine("Name: {0}; Email: {1}", contactItem.FullName, contactItem.Email1Address);
}
}
}
}
We are very sorry for getting to you on this a little late.
What actual issue are you facing while using Aspose API? The API provides the capability to read Outlook Contact .MSG files as well as Distribution lists without the need of having MS Outlook installed.
Please have a look at the following documentation articles:
Working with Outlook Contacts
If you still face issue while retrieving the desired information with the latest version of the API, you can post your query along with sample MSG files to Aspose.Email forum. We will investigate these at our end and assist you further.
I work with Aspose as Developer evangelist.
If using Redemption is an option (I am its author), something like the following should work for reading contacts or distribution lists saved as msg files:
Redemption.RDOSession session = new Redemption.RDOSession();
Redemption.RDOMail msg = session.GetMessageFromMsgFile(#"c:\temp\TestContact.msg");
//is it really a contact? Could be a regular message or an RDODistListItem (all derived from RDOMail)
Redemption.RDOContactItem contact = msg as Redemption.RDOContactItem;
if (contact != null)
{
MessageBox.Show(contact.FirstName);
}
else
{
Redemption.RDODistListItem dl= msg as Redemption.RDODistListItem;
if (dl != null)
{
MessageBox.Show(dl.FileAs);
}
}
This is a piece of code for genrating mail which works until I didnt attach path as a parameter . the thing is if I attach the path it didnt throw any error(no logs). Just the page started being unresponsive,and debugger not even jump to next line.
any help wil help me to understand my mistake . Thanks
public ActionResult Mailsending(string list)
{
try
{
string strIdeas = string.Empty;
string Certpath = System.Configuration.ConfigurationManager.AppSettings["UploadPath"];
List<int> list = new List<int>();
List<string> pramAttachment = new List<string>();
pramAttachment.Add(Server.MapPath(Certpath) + "MyPdf.pdf"); ///Path of the generated pdf.
Submitidlist = new CommonBL().GetSubmiidListForGenerateMail();
new CommonBL().UpdateIsGenerateStatus(ideaidlist, UserID);
foreach (var item in ideaidlist)
{
strIdeas = strIdeas + item.ToString() + ",";
}
GenerateMyPDF(list); //Here pdf is generating
string path = GenerateMail(strIdeas.TrimEnd(','));
if (path != string.Empty)
{
new CommonBL().AddGenerateImagePath(path, UserId);
new MailSender().SendMail((int)eMailType.GenerateMail, null, pramAttachment); // here path is added as parameter,and after this debugger not jump out of this scope.
}
return Json("Mail generated Successfully."); ///no message showing
}
catch (Exception ex)
{
return Json("Error");
}
}
Edit :
public class MailSender : IDisposable
{
public bool SendMail(short mailId, List<KeyValuePair<string, string>> parameters, List<string> attachmentsPath = null);
}
Possibly still leaving lock on the generated PDF, so MailSender is not able to access it due to that exclusive lock. Can you send emails with files previously generated?
adding a point which apparently is also an answer of this question, is :
After debugging whole code, I found that my smtp server is not allowing to send me a mail, so even if the above code is right, it shows processing.
So if anyone is working with above code will work fine.
An update : Now it works fine after configuring my mail service from control panel. So if any one wants to take reference from this can go ahead . the code is fine .
I am currently refining an MS Outlook Add-In to pick up emails that end up in the Junk folder with "legit" addresses and then moving them into the Inbox folder.
This is an occurence that happens a lot for Gmail addresses, and is a bit painstaking for our staff members, who have to manually link those emails to their client accounts.
Has anyone attempted this? I have registered the incoming email event handler to read the Junk folder when an email comes in, but I keep getting an exception. I suspect it has to do with the fact that some of these emails are spam; which simply means that the MailItem will have lots of errors.
Has anyone had the same issue? Here is my code:
public void OutlookApplication_ItemReceived(string entryID)
{
//this.outlookNameSpace = this.application.GetNamespace("MAPI");
//Outlook.MAPIFolder inbox = this.outlookNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
//Outlook.MAPIFolder junkFolder = this.outlookNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderJunk);
if (Properties.Settings.Default.AutoLink || Properties.Settings.Default.EnableLeadLoader)
{
Outlook.MailItem mail = null;
try
{
this.Log("Email detected: incoming");
mail = this.application.Session.GetItemFromID(entryID) as Outlook.MailItem;
this.leadLoaderRecipient = Properties.Settings.Default.LeadLoaderRecipient.ToLower();
Outlook.Recipients recips = mail.Recipients; //That's where its crashing as the object is null... if read from spam folder
foreach (Outlook.Recipient recip in recips)
{
Outlook.PropertyAccessor pa = recip.PropertyAccessor;
string smtpAddress = pa.GetProperty(PR_SMTP_ADDRESS).ToString();
if (Properties.Settings.Default.EnableLeadLoader)
{
if (smtpAddress.ToLower() == this.leadLoaderRecipient)
this.ProcessLead(mail);
}
}
if (Properties.Settings.Default.AutoLink)
{
this.AutoLink(mail, true);
}
}
catch (Exception ex)
{
this.Log("Exception (ItemReceived): " + ex.ToString());
}
finally
{
if (mail != null)
{
Marshal.ReleaseComObject(mail);
}
}
}
}
Looking forward to your thoughts guys! :) TIA!
When exactly does your code run? Is that an Application.NewMailEx event handler? What is the exception?
Try to use the Items.ItemAdd event on the Junk Mail folder instead of using Application.NewMailEx.
First off, does the AWS C# SDK self check itself? Right now, I have code that does stuff like
md5 checking
List<string> msgs = new List<string>();
ReceiveMessageResponse response = this.getMessageRoutine(num);
foreach (Message m in response.ReceiveMessageResult.Message) {
if (m.MD5OfBody.ToUpper() != Global.StringFunctions.CalculateMD5Hash(m.Body)) {
throw new Exception("TODO IMPLEMENT: RECEIVED MESSAGE IS CORRUPT");
}
msgs.Add(m.Body);
}
return msgs;
verifying that the user defined IDs sent out came back in the response, and that the md5 the server generated of the message matches the message sent
foreach (SendMessageBatchResultEntry e in response.SendMessageBatchResult.SendMessageBatchResultEntry) {
foreach (SendMessageBatchRequestEntry r in entry) {
if (r.Id == e.Id) {
if (Global.StringFunctions.CalculateMD5Hash(r.MessageBody) != e.MD5OfMessageBody.ToUpper()) {
throw new Exception("TODO IMPLEMENT THIS: MD5 MISMATCH BETWEEN AWS:LOCAL (" + e.MD5OfMessageBody.ToUpper() + " : " + Global.StringFunctions.CalculateMD5Hash(r.MessageBody)+")");
}
entry.Remove(r);
break;
}
throw new Exception("TODO IMPLEMENT THIS: INVALID ID IN RESPONSE");
}
}
if (entry.Count != 0) {
throw new Exception("TODO IMPLEMENT: NOT ALL MESSAGES SENT HAD A CORRESPONDING CALLBACK");
}
Is there a better implementation of something like this already created, something like
request.checkResponse(response) ?
The most recent version of the AWS SDK for .NET (1.5.23) includes the MD5 hash check as part of sending a single message, sending a batch of messages, and receiving messages. If that does not work for you, we would love to hear why and how we could make it better.
Thanks!