MailKit-MimeKit - How to copy to Sent folder - c#

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);

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.

Send email with previous messages by mailkit (smtp)

My application is windows service that send and get messages from mailbox. Emails are saved in the SQL Server database. Now my application send actual text/html (previous emails text is not included in sending message). I want to add possibility to send email with previous emails text/html. Does mailkit or smtp have feature which will help me to implement this mechanism or I should I collect data about every email and construct text/html by myself.
I want to send emails this way
Now I send emails this way
Here is my example of sending email:
var mimeMessage = new MimeMessage();
var multipart = new Multipart("mixed");
mimeMessage.To.AddRange(GetListOfMailboxAddresses(row.Field<int?>("ToGroup")) ?? new List<MailboxAddress>());
mimeMessage.Cc.AddRange(GetListOfMailboxAddresses(row.Field<int?>("CcGroup")) ?? new List<MailboxAddress>());
mimeMessage.Bcc.AddRange(GetListOfMailboxAddresses(row.Field<int?>("BccGroup")) ?? new List<MailboxAddress>());
mimeMessage.From.Add(new MailboxAddress(row["FromName"].ToString(), PluginHelper.ConfigurationXML.SmtpKonfig.SmtpUzytkownik));
mimeMessage.Sender = new MailboxAddress(row["FromName"].ToString(), PluginHelper.ConfigurationXML.SmtpKonfig.SmtpUzytkownik);
mimeMessage.Subject = row["Subject"].ToString();
var bodyBuilder = new BodyBuilder();
bodyBuilder.HtmlBody = row["HTML"].ToString();
bodyBuilder.TextBody = row["Text"].ToString();
multipart.Add(bodyBuilder.ToMessageBody());
var attachment = new MimePart();
if (Convert.ToInt32(row["SendingEmailId"]) == (int)EmailSendingType.Reply)
{
if (!mimeMessage.Subject.StartsWith("Re:", StringComparison.OrdinalIgnoreCase))
mimeMessage.Subject = "Re:" + mimeMessage.Subject;
ConstructReplyReferences(DataAccess.GetGuidsForReply(Convert.ToInt32(row["ConversationId"]), Convert.ToInt32(row["Id"])), row["ReplyToGuid"].ToString(), mimeMessage);
try
{
ConstructReplyReferencesFromCREW(row.Field<int?>("ObjectNumber"), mimeMessage);
}
catch (Exception ex)
{
LoggerHelper.LogInfo(ex.ToString());
}
}
if (!string.IsNullOrWhiteSpace(row.Field<string>("ReplyEmailInUserWindow")))
{
mimeMessage.ReplyTo.Clear();
mimeMessage.ReplyTo.Add(new MailboxAddress(row.Field<string>("ReplyEmailInUserWindow")));
}
GetAddAttachments(multipart, Convert.ToInt32(row["Id"]));
mimeMessage.Body = multipart;
client.Send(mimeMessage);

Error when sending both an email and a fax with the same SMTP (C#)

I am currently working on a routine that automatically generates a Text from some predefined Settings, and should send that Text either as an Email or a Fax - or even both.
Code looks like this:
SmtpClient smtp = new SmtpClient(Properties.Settings.Default.SmtpServer)
{
UseDefaultCredentials = true
};
if (IsMail)
{
var sendMail = "current users email";
using (MailMessage mm = new MailMessage(sendMail, this.EmailAddress))
{
mm.Subject = this.Subject;
if (!string.IsNullOrEmpty(this.MailBody))
{
mm.Body = this.MailBody.Replace("\n\n", "<br><br>");
mm.IsBodyHtml = true;
}
if (this.IsCcMail)
mm.CC.Add(sendMail);
foreach (var a in Attachments)
mm.Attachments.Add(a);
smtp.Send(mm);
}
}
if (IsFax)
{
var formatedFaxNo = this.CountryPhoneCode + FaxNo.TrimStart('0');
using (MailMessage mm = new MailMessage("current users email", formatedFaxNo + "#fax"))
{
mm.Subject = this.Subject;
if (!string.IsNullOrEmpty(this.MailBody))
{
mm.Body = this.MailBody.Replace("\n\n", "<br><br>");
mm.IsBodyHtml = true;
}
if (IsCcFax)
mm.CC.Add("current users fax" + "#fax");
if (ShowMessageYesNo(Translator.WouldYouLikeToSendTheFaxWithACoverSheet) != System.Windows.MessageBoxResult.Yes)
mm.Headers.Add("EMPTYBODYTEXT", "1");
else
{
var faxBody = Properties.Resources.FaxTemplate.ToString();
mm.Body = string.Format(faxBody,
Translator.Fax, formatedFaxNo,
Translator.From, "current users name",
Translator.Subject, this.Subject,
Translator.Date, DateTime.Now.ToShortDateString(),
this.MailBody?.Replace("\n\n","<br><br>"));
}
foreach (var a in Attachments)
mm.Attachments.Add(a);
smtp.Send(mm);
}
}
If I want to send both an email and a Fax, I get a SMTP exception at the time the Fax is supposed to be sent - the Email is successfully sent before.
The Error only reads
"Error sending Mail"
Which is not really helpful.
So far I've tried:
Sending two mails instead of a Mail and a Fax - works as intended;
Sending two Faxes likewise - works as intended;
Changing the Order and sending the Fax before the Mail - The Fax gets sent, but I get the SMTP exception on sending the mail;
Disposing the SmtpClient after sending the Mail and creating a new one for the Fax - does not change anything;
To me it seems like there is an issue with the SMTP Server I'm trying to send stuff from, but I'm currently not able to change anything about the Server.
Does anyone here have any further suggestions what I could try to fix that Issue?

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);
}

Command Line App Can't Send Email Through Scheduled Tasks

I wrote a small command line utility in C# that sends an email as a result of actions that it takes. The email is sent successfully when it is run manually from the command line, but it doesn't send when its run as a scheduled task. I set it to run with the highest user settings as a scheduled task. There are no firewall settings that would block outgoing emails on the test machine.
Do scheduled tasks run as a user that is restricted from sending emails? I'm not sure if there is any code for sending emails in C# that can set the mailer as an administrator.
Thanks.
Here is the C# code I use for sending an email:
public static void SendNotifications ()
{
string smtpServer = "mailserver.com";
string smtpUser = "a#b.com";
string smtpPassword = "abc123";
// Set the variables for the mail object.
using (MailMessage Email = new MailMessage ())
{
Email.IsBodyHtml = true;
Email.From = new MailAddress (smtpUser);
Email.To.Add ("a1#b.com");
Email.CC.Add ("a2#b.com");
Email.Subject = "Subject";
Email.Body = #"Here is a notification.";
SmtpClient smtp = new SmtpClient (smtpServer);
System.Net.NetworkCredential SMTPUserInfo = new System.Net.NetworkCredential (smtpUser, smtpPassword);
smtp.UseDefaultCredentials = false;
smtp.Credentials = SMTPUserInfo;
try
{
// Send the mail.
smtp.Send (Email);
} // try
catch (Exception ex)
{
// ignore error message
} // catch (Exception e)
} // using (MailMessage Email = new MailMessage ())
}
Assuming you're running the console application via Task Scheduler, one can change the user which runs the scheduler to one which has permission to send email. If you're using DefaultCredentials = true in your code, then this is especially important.
Typically this is done by creating a service account with sufficient permissions to perform the task at hand and nothing more. One can configure which user account will execute the task on the General tab of the task in question within the Task Scheduler. There will be a Change User button. Be sure to check "Run whether the user is logged on or not".

Categories