Search unanswered emails in Gmail
IMAP protocol in RFC3501 introduced \Answered flag. \Answered flag should mark messages that have been answered. This flag can by set by client applications or even by SMTP server, which can be examining In-Reply-To email headers.
Unfortunately if the message is answered through Gmail’s web interface, the \Answered flag will not be set. It will only be set if the messages were answered using an email program that sets this flag.
This means that \Answered flag can’t be used to find not-answered emails.
One option to resolve this problem is to use Gmail IMAP extensions, X-GM-THRID in particular.
We’ll connect to Gmail using IMAP – remember to use SSL and be sure to enable IMAP protocol for Gmail.
As we plan to search all emails, including sent and received ones, we’ll use CommonFolders class to get ‘All Mail’ folder.
Then we’ll get Envelope for each message. Envelope contains GmailThreadId property. It contains thread id to which this email was assigned to by Gmail.
Finally we’ll find threads that contain only one message – those are messages that were not answered.
// C#
using(Imap client = new Imap())
{
client.ConnectSSL("imap.gmail.com");
client.Login("pat@gmail.com", "app-password");
// Select 'All Mail' folder.
List<FolderInfo> folders = client.GetFolders();
CommonFolders common = new CommonFolders(folders);
client.Select(common.AllMail);
// Get envelopes for all emails.
List<long> uids = client.GetAll();
List<Envelope> envelopes = client.GetEnvelopeByUID(uids);
// Group messages by thread id.
var threads = new Dictionary<decimal, List<Envelope>>();
foreach (Envelope envelope in envelopes)
{
decimal threadId = (decimal) envelope.GmailThreadId;
if (threads.ContainsKey(threadId) == false)
threads[threadId] = new List<Envelope>();
threads[threadId].Add(envelope);
}
// Find threads containing single message.
foreach (KeyValuePair<decimal, List<Envelope>> pair in threads)
{
if (pair.Value.Count == 1)
{
Envelope envelope = pair.Value[0];
Console.WriteLine("Gmail message id: {0}; subject: {1}",
envelope.GmailMessageId ,
envelope.Subject);
}
}
client.Close();
}
' VB.NET
Using client As New Imap()
client.ConnectSSL("imap.gmail.com")
client.Login("pat@gmail.com", "app-password")
' Select 'All Mail' folder.
Dim folders As List(Of FolderInfo) = client.GetFolders()
Dim common As New CommonFolders(folders)
client.[Select](common.AllMail)
' Get envelopes for all emails.
Dim uids As List(Of Long) = client.GetAll()
Dim envelopes As List(Of Envelope) = client.GetEnvelopeByUID(uids)
' Group messages by thread id.
Dim threads = New Dictionary(Of Decimal, List(Of Envelope))()
For Each envelope As Envelope In envelopes
Dim threadId As Decimal = CDec(envelope.GmailThreadId)
If threads.ContainsKey(threadId) = False Then
threads(threadId) = New List(Of Envelope)()
End If
threads(threadId).Add(envelope)
Next
' Find threads containing single message.
For Each pair As KeyValuePair(Of Decimal, List(Of Envelope)) In threads
If pair.Value.Count = 1 Then
Dim envelope As Envelope = pair.Value(0)
Console.WriteLine("Gmail message id: {0}; subject: {1}", _
envelope.GmailMessageId, envelope.Subject)
End If
Next
client.Close()
End Using