how to send all gmail drafts using c# or python - c#

I always use gmail to save web clips or notes. I simply create a new mail, edit it and save as draft. Over 2 years I've dumped 1000+ messages in my Gmail draft folder. I want to programmatically send all of them to myself. I did some research, and now I'm able to use python or c# to load my gmail inbox messages via IMAP, or create a mail and send it via SMTP. However I'm still not able to read draft messages and send them to myself.
(Why am I using GMail as note storage instead of note apps such as evernote, MS onenote, or Apple notes? Because email is better supported across any platforms or devices. There are usually pre-installed email clients, and it's easier to find or define a "create new mail" keyboard shortcut than an "export to evernote" keyboard shortcut.)

If you use MailKit, here's how you would do it:
using System;
using System.Net;
using System.Threading;
using MailKit.Net.Imap;
using MailKit.Net.Smtp;
using MailKit;
using MimeKit;
namespace TestClient {
class Program
{
public static void Main (string[] args)
{
using (var client = new ImapClient ()) {
var credentials = new NetworkCredential ("jimbo", "password");
client.Connect (new Uri ("imaps://imap.gmail.com"), CancellationToken.None);
client.Authenticate (credentials, CancellationToken.None);
var folder = client.GetFolder (SpecialFolder.Drafts);
folder.Open (FolderAccess.ReadWrite, CancellationToken.None);
using (var smtp = new SmtpClient ()) {
smtp.Connect (new Uri ("smtps://smtp.gmail.com"), CancellationToken.None);
smtp.Authenticate (credentials, CancellationToken.None);
var indexes = new int[folder.Count];
for (int i = 0; i < folder.Count; i++) {
var message = folder.GetMessage (i, CancellationToken.None);
// if you haven't already specified a recipient, do it now:
message.To.Add (new MailboxAddress ("Jimbo", "jimbo#gmail.com"));
smtp.Send (message, CancellationToken.None);
indexes[i] = i;
}
// if you also want to delete the messages on the IMAP server:
folder.AddFlags (indexes, MessageFlags.Deleted, true, CancellationToken.None);
folder.Close (true, CancellationToken.None);
smtp.Disconnect (true, cancellationToken.None);
}
client.Disconnect (true, cancellationToken.None);
}
}
}
}

Related

MailKit flag downloaded emails as seen

Downloading an email from a server works like a charm. I setup the code to download only
emails that don't have a flag seen. And emails are downloaded without any issues.
After I download the email I need to flag it. I tried this:
using (var client = new ImapClient ()) {
client.Connect ("xxx", 993, SecureSocketOptions.SslOnConnect);
client.Authenticate ("yyy", "zzz");
client.Inbox.Open (FolderAccess.ReadOnly);
var uids = client.Inbox.Search (SearchQuery.NotSeen);
//MessageBox.Show(uids[0].ToString());
foreach (var uid in uids) {
var message = client.Inbox.GetMessage (uid);
// write the message to a file
message.WriteTo (string.Format ("{0}.eml", uid));
client.Inbox.SetFlags(uid, MessageFlags.Seen, true);
}
client.Disconnect (true);
"client.Inbox.SetFlags(uid, MessageFlags.Seen, true);"
did I use this correctly? Because it is not marking the downloaded messages. And if i check emails in inbox, they are still as not seen.

MailKit-MimeKit - How to copy to Sent folder

I ama able to sent SMTP emails using MailKit & MimeKit and outlook is the client tool receiving these mails. Below code has been used and my Inbox has emails received.
var email = new MimeMessage
{
Sender = MailboxAddress.Parse("<<from>>")
};
email.To.Add(MailboxAddress.Parse("<<to>>"));
email.Subject = "Test mail from Jaish";
var builder = new BodyBuilder();
builder.TextBody = "This is a test mail from Jaish Mathews";
email.Body = builder.ToMessageBody();
using var smtp = new SmtpClient();
smtp.LocalDomain = "<<domain>>";
smtp.Timeout = 10000;
smtp.Connect("<<host>>", 25, SecureSocketOptions.None);
var mailboxes = email.To.Mailboxes;
//Sending email
await smtp.SendAsync(email);
//Disconnecting from smtp
smtp.Disconnect(true);
Issue is that my "Sent" folder isn't keeping any track of these emails sent. How can I manually copy to my "Sent" folder"
Before I explain how to save the message in your Sent IMAP folder, I first want to bring attention to a few things.
smtp.Timeout = 10000; It's probably best to not override the default timeout (which I believe is 120,000. 10000 is 10 seconds).
You currently have a mix of sync and async calls to the SmtpClient. You should pick sync or async and stick with it (at least if it's all within the same method).
Okay, now on to your question.
using var imap = new ImapClient ();
await imap.ConnectAsync ("<<host>>", 143 /* or 993 for SSL */, SecureSocketOptions.Auto).ConfigureAwait (false);
await imap.AuthenticateAsync ("username", "password").ConfigureAwait (false);
IMailFolder sent = null;
if (imap.Capabilities.HasFlag (ImapCapabilities.SpecialUse))
sent = imap.GetFolder (SpecialFolder.Sent);
if (sent == null) {
// get the default personal namespace root folder
var personal = imap.GetFolder (imap.PersonalNamespaces[0]);
// This assumes the sent folder's name is "Sent", but use whatever the real name is
sent = await personal.GetSubfolderAsync ("Sent").ConfigureAwait (false);
}
await sent.AppendAsync (email, MessageFlags.Seen).ConfigureAwait (false);
await imap.DisconnectAsync (true).ConfigureAwait (false);

How to parse the body of an email in Gmail, download and delete

I am using Mimekit to receive mail from Gmail using C# for IOT notifications, which seems to be working.
I would like to do the following:
Log in to Gmail
Search inbox mail containing a specific keyword in subject or body.
Parse the body like you would a text file in C#
Download a attachment (test.txt)
Delete
At this point I am able to login successfully and retrieve a list of folders and matches for a string.
Here is my code:
using (var client = new ImapClient())
{
client.Connect("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
// disable OAuth2 authentication unless you are actually using an access_token
client.AuthenticationMechanisms.Remove("XOAUTH2");
client.Authenticate("user#gmail.com", "password");
MessageBox.Show("we're connected");
// The Inbox folder is always available on all IMAP servers...
var inbox = client.Inbox;
inbox.Open(FolderAccess.ReadOnly);
//1. search for all messages containing the string test123
var query = SearchQuery.FromContains("test123");
foreach (var uid in inbox.Search(query))
{
var message = inbox.GetMessage(uid);
System.Diagnostics.Debug.WriteLine("[match] {0}: {1}", uid, message.Subject);
//2. Show all folders in Personal
var personal = client.GetFolder(client.PersonalNamespaces[0]);
foreach (var folder in personal.GetSubfolders(false))
System.Diagnostics.Debug.WriteLine("[folder] {0}", folder.Name);
}
client.Disconnect(true);
MessageBox.Show("disconnected ");
}
So my question is: How do I accomplish steps 3 , 4 and 5?
using (var client = new ImapClient ()) {
client.Connect ("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
// disable OAuth2 authentication unless you are actually using an access_token
client.AuthenticationMechanisms.Remove ("XOAUTH2");
// 1. Log in to Gmail
client.Authenticate ("user#gmail.com", "password");
// 2. Search inbox mail containing a specific keyword in subject or body.
client.Inbox.Open (FolderAccess.ReadWrite);
var query = SearchQuery.SubjectContains ("123").Or (SearchQuery.BodyContains ("123"));
foreach (var uid in client.Inbox.Search (query)) {
// 3. Parse the body like you would a text file in C#
// This downloads and parses the full message:
var message = client.Inbox.GetMessage (uid);
// 4. Download a attachment (test.txt)
// No need to download an attachment because you already
// downloaded it with GetMessage().
// Here's how you could get the "test.txt" attachment:
var attachment = message.BodyParts.OfType<MimePart> ()
.FirstOrDefault (x => x.FileName == "test.txt");
// 5. Delete
// This marks the message as deleted, but does not purge it
// from the folder.
client.Inbox.AddFlags (uid, MessageFlags.Deleted, true);
}
// Purge the deleted messages (if you use Thunderbird, this is aka "Compact Folders")
client.Inbox.Expunge ();
client.Disconnect (true);
}

Getting unread count from gmail using C#

I've been trying to get the count of unread emails in Gmail but I'm encountering some problems. I did a search and I found ImapX library that should help me achieve this, but the code I found here on StackOverFlow on previews questions doesn't work. This is my code right now:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string username = "my_email#gmail.com";
string passwd = "my_pass";
int unread = 0;
ImapClient client = new ImapClient("imap.gmail.com", 993, true);
bool result = client.IsConnected;
if (result)
Console.WriteLine("Connection Established");
result = client.Login(username, passwd); // <-- Error here
if (result)
{
Console.WriteLine("Logged in");
FolderCollection folders = client.Folders;
// Message messages = client.Folders["INBOX"].Messages;
foreach (ImapX.Message m in client.Folders["INBOX"].Messages)
{
if (m.Seen == false)
unread++;
}
Console.WriteLine(unread);
}
}
}
}
The Error is:
The selected authentication mechanism is not supported" on line 26
which is result = client.Login(username, passwd);
Sample from ImapX:
var client = new ImapX.ImapClient("imap.gmail.com", 993, true);
client.Connection();
client.LogIn(userName, userPassword);
var messages = client.Folders["INBOX"].Search("ALL", true);
Maybe you have enabled Two-factor authentication and you need generate application password. Othery way you will receive an e-mail warning that something is trying to access your mailbox and you must add your application as an exception. As an alternate solution you can try https://github.com/jstedfast/MailKit sample code at the bottom of the README
Most likely, gmail is looking for you to do a STARTTLS command, which it appears ImapX does not support. If you look at the response to the IMAPX1 CAPABILITY request, you'll likely see a "LOGINDISABLED" element, which means the server won't accept the "LOGIN" statement yet. So even if you UseSSL, the server (Microsoft Exchange in my case) is still looking for the STARTTLS command before it will let me LOGIN.
You have to make the connection.
ImapClient client = new ImapClient("imap.gmail.com", 993, true);
client.Connect();
bool result = client.IsConnected;
So if you added the line client.Connect(), I think it solves your problem.

AE.Net.Mail not able to connect to outlook.office365.com IMAP

I am finding that I am unable to connect to outlook.office365.com's IMAP server using AE.Net.Mail. The code is very simple:
this._imapClient = new ImapClient(imapServer, username, password, AE.Net.Mail.AuthMethods.Login, port, enableSSL)
I find that I can connect to GMail with no issues, but office365 outlook will not connect, I keep getting timeouts. I've verified the IMAP settings by putting them in to Outlook and in to Thunderbird.
Has anyone else had trouble connecting AE.Net.Mail to Office365's IMAP server?
AE.Net.Mail is quite buggy and has not seen any development in over a year last I checked. I would recommend using MailKit instead.
I just confirmed that MailKit works with Office365.com with the following code snippet:
using (var client = new ImapClient ()) {
client.Connect ("outlook.office365.com", 993, true);
client.Authenticate ("username", "password");
// get the unread messages
var uids = client.Inbox.Search (SearchQuery.NotSeen);
foreach (var uid in uids) {
var message = client.Inbox.GetMessage (uid);
}
client.Disconnect (true);
}
Hope that helps.
Found I am able to connect by increasing the timeouts:
_imapClient.ServerTimeout = 120000;
_imapClient.IdleTimeout = 120000;
_imapClient.Connect(_imapServer, _port, _enableSSL, false);
_imapClient.Login(_username, _password);
_imapClient.SelectMailbox("Inbox");

Categories