Send email with previous messages by mailkit (smtp) - c#

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

Related

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

MailMessage sends mail with empty subject and attachments

So I'm trying to send an email through my relay smtp with an html body, subject and optional attachments. The sending works without exceptions however, the mail which is being sent ends up with an empty subject and no attachments which should get files from the wwwroot folder of my web application which is being hosted on the same domain as my API and console app. This console app will be called from the task scheduler. This program has my API as dependency so that it can call the ProcessQueue task. this one is being called correctly from my console application. To get data for the email the code will retreive data from the MailQueue table and then fill the mailmessage like so:
public async Task ProcessQueue(int range, bool send)
{
SmtpClient client = new SmtpClient
{
Host = "outbound.domain",
Port = 587,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("email#domain.com", "")
};
var items = await _context.MailQueues.Take(range).ToListAsync();
MailMessage message = new MailMessage();
foreach (var item in items)
{
try
{
message.From = new MailAddress(item.From);
message.Subject = item.Subject; // The subject is being filled correctly in my situation, but when the email arrives it isn't
message.IsBodyHtml = true;
message.To.Add(item.To);
message.Body = item.Content;
if (send)
{
AddAttachments(message, item.Docs);
client.Send(message);
_context.MailQueues.Remove(item);
message.To.Clear();
}
}
catch(Exception ex)
{
item.Exception = ex.ToString();
_context.Entry(item).State = System.Data.Entity.EntityState.Modified;
}
}
The attachment method:
private void AddAttachments(MailMessage message, string docs)
{
if (docs != null)
{
List<string> list = JsonConvert.DeserializeObject<List<string>>(docs);
foreach (string item2 in list)
{
Attachment item = new Attachment(HttpContext.Current.Server.MapPath("/wwwroot/documents/") + item2)
{
Name = item2
};
message.Attachments.Add(item);
}
}
}
The structure of my domain:
domain.com > webapplicatie (contains my web app and its wwwroot folder)
domain.com > webapi (contains my web api)
domain.com > mailqueuer (the location of my console application)
My goal is to send the message with optional attachments, which are located in the web app's wwwroot folder, and its subject. All the data of the MailQueue objects are filled! but still I get this problem.
Does somebody know a solution to this?
I solved this problem by putting the database and smtp logic for the MailQueue into the console application. I don't exactly know why my question isn't working but I'm open for answers and suggestions!

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?

Sendgrid C# bulk email X-SMTPAPI header not working

I am trying to send email with SendGrid to multiple recipients in an ASP.Net C# web application
According to the SendGrid documentation I need to add X-SMTPAPI header to my message in JSON formatted string. I do so, for first check I just added a hand-typed string before building my json email list progamatically here is my code:
string header = "{\"to\": [\"emailaddress2\",\"emailaddress3\"], \"sub\": { \"%name%\": [\"Ben\",\"Joe\"]},\"filters\": { \"footer\": { \"settings\": { \"enable\": 1,\"text/plain\": \"Thank you for your business\"}}}}";
string header2 = Regex.Replace(header, "(.{72})", "$1" + Environment.NewLine);
var myMessage3 = new SendGridMessage();
myMessage3.From = new MailAddress("emailaddress1", "FromName");
myMessage3.Headers.Add("X-SMTPAPI", header2);
myMessage3.AddTo("emailaddress4");
myMessage3.Subject = "Test subject";
myMessage3.Html = "Test message";
myMessage3.EnableClickTracking(true);
// Create credentials, specifying your user name and password.
var credentials = new NetworkCredential(ConfigurationManager.AppSettings["xxxxx"], ConfigurationManager.AppSettings["xxxxx"]);
// Create an Web transport for sending email.
var transportWeb = new Web(credentials);
// Send the email, which returns an awaitable task.
transportWeb.DeliverAsync(myMessage3);
But it just seems to ignore my header, and sends the email to the one email "emailaddress4" used in "addto".
According the documentation if the header JSON is parsed wrongly, then SendGrid sends an email about the error to the email address set in "FROM" field, but I get no email about any error.
Anyone got any idea?
For me using the latest 9.x c# library the only way I could solve this was by using the MailHelper static functions like this:
var client = new SendGridClient(HttpClient, new SendGridClientOptions { ApiKey = _sendGridApiKey, HttpErrorAsException = true });
SendGridMessage mailMsg;
var recipients = to.Split(',').Select((email) => new EmailAddress(email)).ToList();
if (recipients.Count() > 1)
{
mailMsg = MailHelper.CreateSingleEmailToMultipleRecipients(
new EmailAddress(from),
recipients,
subject,
"",
body);
}
else
{
mailMsg = MailHelper.CreateSingleEmail(
new EmailAddress(from),
recipients.First(),
subject,
"",
body);
}
if (attachment != null)
{
mailMsg.AddAttachment(attachment.Name,
attachment.ContentStream.ToBase64(),
attachment.ContentType.MediaType);
}
var response = await client.SendEmailAsync(mailMsg).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
_log.Trace($"'{subject}' email to '{to}' queued");
return true;
}
else {
throw new HttpRequestException($"'{subject}' email to '{to}' not queued");
}
I'm not sure why you wouldn't recieve any errors at your FROM address, but your JSON contains the following flaws:
, near the end makes the string invalid json
spaces around the first % in %name%, that might make sendgrid think it's an invalid substitution tag
if you use the X-SMTPAPI header to specify multiple recipients, you are not supposed to add a standard SMTP TO using AddTo().
Besides that, you didn't wrap the header at 72 characters (see the example in the documentation).
I figured that however the X-SMTPAPI documentation talks about passing the header as JSON, the API itself expects it as a parameter, containing Ienumerable string. So the working code is:
var myMessage3 = new SendGridMessage();
myMessage3.From = new MailAddress("email4#email.com", "Test Sender");
myMessage3.AddTo("email2#email.com");
myMessage3.Subject = "Új klubkártya regisztrálva";
myMessage3.Html = "Teszt üzenet";
myMessage3.EnableClickTracking(true);
/* SMTP API
* ===================================================*/
// Recipients
var addresses = new[]{
"email2#email.com", "email3#email.com"
};
//string check = string.Join(",", addresses);
myMessage3.Header.SetTo(addresses);
// Create credentials, specifying your user name and password.
var credentials = new NetworkCredential(ConfigurationManager.AppSettings["xxxxxxx"], ConfigurationManager.AppSettings["xxxxxxxxx"]);
// Create an Web transport for sending email.
var transportWeb = new Web(credentials);
// Send the email, which returns an awaitable task.
transportWeb.DeliverAsync(myMessage3);

How to send automated emails?

I am working in C# and Sql server. I have a table Email that contains fields from, to, subject, body, CC, BCC etc. When something happens in it saves the notification. I want to send the mail notification that newly inserted in Email table automatically. Is there is a way in SQL Server??? Which send emails automatically and deletes the record from the table. OR what is the efficient way for this task (from C#code or else).
Thanks,
Girish
What I would do is set up your sql server to have sql Mail and then use a trigger against your table to fire the mail event and then delete the row.
Here's how to configure your sever for sql mail
SQL Mail Config
You are talking about two problems -
1. Send email from c#
2. Delete from table
For #1, refer here http://social.msdn.microsoft.com/Forums/en/netfxnetcom/thread/a75533eb-131b-4ff3-a3b2-b6df87c25cc8
try
{
var fromAddress = new MailAddress("address#gmail.com", "Support");
var toAddress = new MailAddress(user.email, user.username);
const string subject = "Processing";
var smtp = new SmtpClient
{
Host = "smtp.gmail.com",
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("username", "password")
};
using (var message = new MailMessage(fromAddress, toAddress)
{
Subject = subject,
Body = dataToSend
})
{
message.IsBodyHtml = true;
smtp.Send(message);
}
}
catch (Exception)
{
Model.Message = "Exception Occured During Mail Sending";
}

Categories