Skip to content

Instantly share code, notes, and snippets.

@guibranco
Created September 22, 2019 02:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guibranco/fa37640393e6d027eb03d53bbbfdc509 to your computer and use it in GitHub Desktop.
Save guibranco/fa37640393e6d027eb03d53bbbfdc509 to your computer and use it in GitHub Desktop.
A simple C# dotnet client to access a POP3 account and delete messages by some rules (from, subject, etc)
namespace MailCleaner
{
//https://github.com/rfinochi/pop3dotnet
//PM> Install-Package Pop3
using Pop3;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
static class Program
{
private static Int32 _counter;
private static readonly HashSet<String> FromHashSet = new HashSet<String>();
static void Main()
{
Console.WriteLine("Hello World!");
Start().Wait();
}
private static async Task Start()
{
try
{
//The worker deletes up to 100 messages per time
//The worker is called 100 times
// 100 x 100 = up to 10.000 messages deleted per execution
for (var x = 0; x < 100; x++)
{
await DoWork();
_counter = 0;
}
if (!FromHashSet.Any())
return;
//Stores in the log.txt file the "From"s that was not deleted
using (var file = File.OpenWrite("log.txt"))
{
foreach (var from in FromHashSet)
{
var buffer = new UTF8Encoding(true).GetBytes($"{from}\r\n");
await file.WriteAsync(buffer, 0, buffer.Length);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static async Task DoWork()
{
//PM> Install-Package Pop3 -Version 2.2.8
var pop = new Pop3Client();
//change the following lines with your server data and credentials of your account
await pop.ConnectAsync(
"pop_server",
"account_address",
"account_password",
true);
var messages = await pop.ListAsync();
var pop3Messages = messages as Pop3Message[] ?? messages.ToArray();
Console.WriteLine($"Total messages: {pop3Messages.Length}");
foreach (var message in pop3Messages)
{
Console.WriteLine(new String('=', 100));
await pop.RetrieveHeaderAsync(message);
Console.WriteLine($"{Decode(message.Subject)} - {message.Date}");
await Validate(pop, message);
if (_counter >= 100)
break;
}
await pop.DisconnectAsync();
}
private static async Task Validate(Pop3Client pop, Pop3Message message)
{
if (!message.From.Equals("unwanted_from_address@example.com"))
{
Console.WriteLine($"Message left from {message.From}");
FromHashSet.Add(message.From);
return;
}
_counter++;
Console.WriteLine($"Deleting message from {message.From}");
await pop.DeleteAsync(message);
}
private static String Decode(String mimeString)
{
var regex = new Regex(@"=\?(?<charset>.*?)\?(?<encoding>[qQbB])\?(?<value>.*?)\?=");
var encodedString = mimeString;
var decodedString = String.Empty;
while (encodedString.Length > 0)
{
var match = regex.Match(encodedString);
if (match.Success)
{
// If the match isn't at the start of the string, copy the initial few chars to the output
decodedString += encodedString.Substring(0, match.Index);
var charset = match.Groups["charset"].Value;
var encoding = match.Groups["encoding"].Value.ToUpper();
var value = match.Groups["value"].Value;
if (encoding.Equals("B"))
{
// Encoded value is Base-64
var bytes = Convert.FromBase64String(value);
decodedString += Encoding.GetEncoding(charset).GetString(bytes);
}
else if (encoding.Equals("Q"))
{
// Encoded value is Quoted-Printable
// Parse looking for =XX where XX is hexadecimal
var regx = new Regex("(\\=([0-9A-F][0-9A-F]))", RegexOptions.IgnoreCase);
decodedString += regx.Replace(value, delegate (Match m)
{
var hex = m.Groups[2].Value;
var iHex = Convert.ToInt32(hex, 16);
// Return the string in the charset defined
var bytes = new Byte[1];
bytes[0] = Convert.ToByte(iHex);
return Encoding.GetEncoding(charset).GetString(bytes);
});
decodedString = decodedString.Replace('_', ' ');
}
else
{
// Encoded value not known, return original string
// (Match should not be successful in this case, so this code may never get hit)
decodedString += encodedString;
break;
}
// Trim off up to and including the match, then we'll loop and try matching again.
encodedString = encodedString.Substring(match.Index + match.Length);
}
else
{
// No match, not encoded, return original string
decodedString += encodedString;
break;
}
}
return decodedString;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment