Posts Tagged ‘X-GM-THRID’

Search unanswered emails in Gmail

Friday, November 1st, 2013

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@limilabs.com","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@limilabs.com", "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

Create Gmail url-ID via IMAP

Tuesday, August 30th, 2011

This is Gmail link that points to certain conversation (entire thread):

https://mail.google.com/mail/u/0/#inbox/13216515baefe747

“13216515baefe747” is the Gmail thread-ID in hex.

Here’s the code that:

  1. Selects “All Mail” folder
  2. Gets the newest message UID
  3. Obtains Gmail thread ID for this message (X-GM-THRID)
  4. Converts it to hex
  5. Creates the url that points to the Gmail conversation
// C# version

using (Imap client = new Imap())
{
    client.ConnectSSL("imap.gmail.com");
    client.UseBestLogin("pat@gmail.com", "password");

    // Select 'All Mail' folder
    CommonFolders common = new CommonFolders(client.GetFolders());
    client.Select(common.AllMail);

    // get IMAP uid of the newest message
    long lastUid = client.GetAll().Last();

    // get message info
    MessageInfo info = client.GetMessageInfoByUID(lastUid);

    // extract Gmail thread ID
    decimal threadId = info.Envelope.GmailThreadId;
    string threadIdAsHex = threadId.ToString("x");

    // create url
    string url = string.Format(
        "https://mail.google.com/mail/u/0/#inbox/{0}",
        threadIdAsHex);

    Console.WriteLine(url);

    client.Close();
}

' VB.NET version

Using client As New Imap()
	client.ConnectSSL("imap.gmail.com")
	client.UseBestLogin("pat@gmail.com", "password")

	' Select 'All Mail' folder
	Dim common As New CommonFolders(client.GetFolders())
	client.Select(common.AllMail)

	' get IMAP uid of the newest message
	Dim lastUid As Long = client.GetAll().Last()

	' get message info
	Dim info As MessageInfo = client.GetMessageInfoByUID(lastUid)

	' extract Gmail thread ID
	Dim threadId As Decimal = info.Envelope.GmailThreadId
	Dim threadIdAsHex As String = threadId.ToString("x")

	' create url
	Dim url As String = String.Format( _
		"https://mail.google.com/mail/u/0/#inbox/{0}", _
		threadIdAsHex)

	Console.WriteLine(url)

	client.Close()
End Using

Here you can find some more information about how to search by X-GM-THRID and all other Gmail IMAP extensions.

Gmail extensions in Mail.dll

Monday, June 13th, 2011


Here’s the list of Gmail IMAP protocol extensions implemented in Mail.dll:

  • Extension of the LIST command: XLIST
  • Extension of the SEARCH command: X-GM-RAW
  • Access to the Gmail unique message ID: X-GM-MSGID
  • Access to the Gmail thread ID: X-GM-THRID
  • Access to Gmail labels: X-GM-LABELS
  • OAuth and OAuth 2.0: XOAUTH, XOAUTH2

You can read on how to use Mail.dll with Gmail in the following articles:

OAuth 2.0

OAuth 1.0

Search Gmail thread id

Sunday, June 12th, 2011

Gmail provides a thread ID to associate groups of messages in the same manner as in the Gmail web interface.

Retrieval of this thread ID is supported via the X-GM-THRID attribute on the FETCH command.

The thread ID is a 64-bit unsigned integer.

The X-GM-THRID attribute may also be used in the SEARCH command to find the UIDs of messages in a given thread.

// C# version

using (Imap imap = new Imap())
{
    imap.ConnectSSL("imap.gmail.com");
    imap.UseBestLogin("pat@gmail.com", "password");

    // Select 'All Mail' folder
    CommonFolders common = new CommonFolders(client.GetFolders());
    client.Select(common.AllMail);

    long newestMessageUID = imap.GetAll().Last();
    var threadId = imap.GetEnvelopeByUID(newestMessageUID).GmailThreadId;

    List<long> uids = imap.Search().Where(
        Expression.GmailThreadId(threadId));

    foreach (MessageInfo info in imap.GetMessageInfoByUID(uids))
    {
        Console.WriteLine("{0} - {1}",
            info.Envelope.GmailThreadId,
            info.Envelope.Subject);
    }

    imap.Close();
}
' VB.NET version

Using imap As New Imap()
	imap.ConnectSSL("imap.gmail.com")
	imap.UseBestLogin("pat@gmail.com", "password")

	' Select 'All Mail' folder
	Dim common As New CommonFolders(client.GetFolders())
	client.Select(common.AllMail)

	Dim newestMessageUID As Long = imap.GetAll().Last()
	Dim threadId = imap.GetEnvelopeByUID(newestMessageUID).GmailThreadId

	Dim uids As List(Of Long) = imap.Search().Where( _
		Expression.GmailThreadId(threadId))

	For Each info As MessageInfo In imap.GetMessageInfoByUID(uids)
	    Console.WriteLine("{0} - {1}", _
                info.Envelope.GmailThreadId, _
                info.Envelope.Subject)
	Next

	imap.Close()
End Using

You can learn more about this Gmail IMAP extension here:
code.google.com/apis/gmail/imap/#x-gm-thrid

Get Gmail thread id

Sunday, June 12th, 2011

Gmail provides a thread ID to associate groups of messages in the same manner as in the Gmail web interface.

Retrieval of this thread ID is supported via the X-GM-THRID attribute on the FETCH command.

The thread ID is a 64-bit unsigned integer.

// C# version

using (Imap imap = new Imap())
{
    imap.ConnectSSL("imap.gmail.com");
    imap.UseBestLogin("pat@gmail.com", "password");

    imap.SelectInbox();

    List<long> uids = imap.GetAll();
    List<messageInfo> infos = imap.GetMessageInfoByUID(uids);

    foreach (MessageInfo info in infos)
    {
        Console.WriteLine("{0} - {1}",
            info.Envelope.GmailThreadId,
            info.Envelope.Subject);
    }

    imap.Close();
}
' VB.NET version

Using imap As New Imap()
	imap.ConnectSSL("imap.gmail.com")
	imap.UseBestLogin("pat@gmail.com", "password")

	imap.SelectInbox()

	Dim uids As List(Of Long) = imap.GetAll()
	Dim infos As List(Of MessageInfo) = imap.GetMessageInfoByUID(uids)

	For Each info As MessageInfo In infos
	    Console.WriteLine("{0} - {1}", _
                info.Envelope.GmailThreadId, _
                info.Envelope.Subject)
	Next

	imap.Close()
End Using

You can learn more about this Gmail IMAP extension here:
code.google.com/apis/gmail/imap/#x-gm-thrid