Connect to Gmail via POP using C# .NET

Setup

First you need to do two things to get your gmail account ready:

1) Enable POP communication if not already. You can do this by logging into gmail and going to settings (the gear in the top-right corner -> Settings), Forwarding and POP/IMAP, and enabling it there.
2) Enable less safe application communication. You can do this visiting this link and choosing to enable.

Using TcpClient to connect

The class:

internal class Pop3Client : IDisposable
{
	private readonly string mailServer;
	private readonly int port;
	private SslStream SecureStream;
	private StreamReader NetReader;

	internal Pop3Client(string mailServer, int port) 
	{
		this.mailServer = mailServer;
		this.port = port;
	}

	internal void Connect() 
	{
		var client = new TcpClient(mailServer, port);
		SecureStream = new SslStream(client.GetStream());
		SecureStream.AuthenticateAsClient(mailServer);
		NetReader = new StreamReader(SecureStream);
		var result = NetReader.ReadLine(); // Writes "+OK Gpop ready" on success
		Console.WriteLine(result);
	}

	internal void Login(string userName, string password) 
	{
		var user = Encoding.UTF8.GetBytes(string.Format("USER {0}{1}", userName, Environment.NewLine));
		var pw = Encoding.UTF8.GetBytes(string.Format("PASS {0}{1}", password, Environment.NewLine));
		SecureStream.Write(user);
		var result = NetReader.ReadLine(); // Writes "+OK send PASS" on success
		Console.WriteLine(result);
		SecureStream.Write(pw);
		result = NetReader.ReadLine(); // Writes "+OK Welcome." on success
		Console.WriteLine(result);
	}

	internal void RetrieveMessage(int messageNumber) 
	{
		var cmd = Encoding.UTF8.GetBytes(string.Format("RETR {0}{1}", messageNumber, Environment.NewLine));
		SecureStream.Write(cmd);
		var cmdResult = NetReader.ReadLine(); // Writes "+OK message follows" on success
		string line = null;
		var result = new StringBuilder();
		Console.WriteLine(NetReader.CurrentEncoding); 
		while (line != ".") 
		{
			line = NetReader.ReadLine(); // Read in each line 
			result.Append(line + Environment.NewLine); // And append it to our result
		}

		Console.WriteLine(result);
	}

	public void Dispose()
	{
		if (SecureStream != null)
			SecureStream.Dispose();
		if (NetReader != null)
			NetReader.Dispose();
	}
}

Usage

using (var client = new Pop3Client("pop.gmail.com", 995)) 
{
	client.Connect();
	client.Login("yourEmail@gmail.com", "yourPassword");
	client.RetrieveMessage(1);

	Console.WriteLine(client);
	Console.ReadLine();
}

When connecting via POP to Gmail, we need the mail server, port, and in this case I’m using the TcpClient class for communication and the SslStream class for authentication. Optionally I’ve included the StreamReader class to assist in reading, though you could use the SslStream to achieve the same effect.

So basically the process is simple: You write a command to the server, and receive a response. Whenever you write, make sure to include a newline character to complete it. I’m using UTF8 Encoded bytes to write, and then just reading that data back. The POP commands I’m using here are:

Commands

USER
PASS
RETR

The responses always start with one of the following, depending on success/failure

+OK
-ERR

One last thing. When retrieving a message, the returned message will have some sort of encoding. Quoted printable is a common one, and in order to get the complete message I would recommend decoding the message once you return it. I found the method here for decoding was effective for what I needed, and I recommend it for anyone else who needs it.

Copied here in case it gets taken down or removed (from www.dpit.co.uk)

private string DecodeQuotedPrintable(string input)  
{  
	var occurences = new Regex(@"(=[0-9A-Z][0-9A-Z])+", RegexOptions.Multiline);  
	var matches = occurences.Matches(input);  
	foreach (Match m in matches)  
	{  
		byte[] bytes = new byte[m.Value.Length / 3];  
		for (int i = 0; i < bytes.Length; i++)  
		{  
			string hex = m.Value.Substring(i * 3 + 1, 2);  
			int iHex = Convert.ToInt32(hex, 16);  
			bytes[i] = Convert.ToByte(iHex);  
		}

		input = input.Replace(m.Value, Encoding.Default.GetString(bytes));  
	}
  
	return input.Replace("=rn", "");  
}  

Wrapping Up

This same technique can be applied for IMAP as well with only a little tweaking. You’d need the server name, port, and instead of POP commands just use IMAP commands.

So hopefully this has been informative, if you’ve enjoyed reading please leave a comment below or see if I’ve made any mistakes or a better way of doing this I would love to hear it, thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *