karastojko/mailio

Parsing failure.

Closed this issue · 8 comments

I have a bit of a peculiar issue.

I have the following code:

try
{
	mailio::imaps connection("imap.gmail.com", 993);
	connection.authenticate(EMAIL, PASSWORD, mailio::imaps::auth_method_t::LOGIN);
	connection.select("INBOX");

	std::list<unsigned long> messages;

	std::list<mailio::imaps::search_condition_t> conditions;
	conditions.push_back(mailio::imaps::search_condition_t(mailio::imaps::search_condition_t::SUBJECT, "[GLFW] Summary"));
	connection.search(conditions, messages, true);
		
	mailio::message message;
	message.line_policy(mailio::codec::line_len_policy_t::VERYLARGE, mailio::codec::line_len_policy_t::VERYLARGE);

	for (unsigned long message_uid : messages)
	{
		connection.fetch(message_uid, message, true);
		std::cout << message.subject_raw() << std::endl;
	}
}
catch (mailio::imap_error& exception)
{
	printf("IMAP error: %s", exception.what());
}

the std::cout << message.subject_raw() << std::endl; line in the for loop results in the imap_error exception being thrown. exception.what() returns Parsing failure.

Here is the peculiar part. The search returns thirteen emails. First time I run the program the exception is thrown immediately. Second time it parses the first found email and then the exception is thrown. Third time it successfully parses the first two emails, then the exception is thrown, etc. This makes no sense to me.

Is there any reason I should look out for? Immediately it seems to be a memory issue, but I have no idea why running the program over and over can allow it to parse some data.

I have made the most peculiar discovery! The parsing error occurs if the message is unread and does not when the message is read! I have no clue why this could be the case, but I am certainly hoping for a fix.

the std::cout << message.subject_raw() << std::endl; line in the for loop results in the imap_error exception being thrown. exception.what() returns Parsing failure.

message.subject_raw() throws no exception.
it may be thrown in fetch method

My apologies! I double checked and that is indeed the case. However, I still find it a bit absurd that an unread email causes an issue and a read email does not. I am sure there is a perfectly reasonable explanation, but surely other people must have run into this issue? Is there a known fix to this?

Additional information: when retrieving an email with header_only selected, there is no issue. It is only when I want the full email.

Interesting, let me try to reproduce it.

I tested this case and share what I found.

gmail imap server changed email state from unread to read when fetching whole RFC822.
in that case, it sends one more untagged response which does not include RFC822.

>>> 3 UID FETCH 62 (UID RFC822)\r\n

<<< * 2 FETCH (UID 62 RFC822 {5140}\r\n
<<< ... # mime data
<<<  FLAGS (\Seen))\r\n
<<< * 2 FETCH (UID 62 FLAGS (\Seen))\r\n # one more untagged response without RFC822 data
<<< 3 OK Success\r\n

mailio::imap::fetch throws Parsing failure imap_error by following line because it didn't get literal response.

throw imap_error("Parsing failure.");

Gmail and Outlook send more tokens after the string literal, in this case this is the line FLAGS (\Seen)).
@yjm6560 you are right about the line that throws the exception, thanks for the analysis. If I remove it, then it seems that the message is correctly read even it is unread. As a quick fix, this else statement can be removed, so the unread messages should be correctly read.
I am working on a proper fix to allow parser also to check this additional tokens. I have IMAP auto tests not published here which I'll have also to run in order to check whether something else is broken.
Sorry for taking so long to reply, I am dealing now with this problem.

You can try this fix. I have to test it a little bit more.

The fix does not break existing functionalities, so I am closing it.