I have a method in my MVC Controller which I am trying to call an API from in order to send an email (The Mail Message is generated in the MVC Method)
Create Mail message is as follows and this works fine.
public static MailMessage CreateMailMessage(string from,
string to,
string cc,
string bcc,
string subject,
string body,
List<Attachment> attachments,
string differentServer,
bool eatError)
{
MailMessage mm = new MailMessage();
mm.From = new MailAddress(from);
mm.Subject = subject;
mm.Body = body;
mm.IsBodyHtml = true;
//send to multiple addresses separated by semi-colon or comma
if (!string.IsNullOrEmpty(to))
{
var toAddresses = to.Split(new char[] { ';', ',' });
foreach (string toAddress in toAddresses)
{
if (!string.IsNullOrWhiteSpace(toAddress))
mm.To.Add(toAddress);
}
}
if (!string.IsNullOrEmpty(cc))
{
mm.CC.Add(cc);
}
if (!string.IsNullOrEmpty(bcc))
{
mm.Bcc.Add(bcc);
}
if (attachments != null)
{
foreach (Attachment attachment in attachments)
{
mm.Attachments.Add(attachment);
}
}
return mm;
}
However in order to send the email I need to write and call a WebAPI method - sending the email is fine - just not sure how to post the mail message and some other properties to a WebAPI Method?
So My WebAPI method at the minute is like:
/// <summary>
/// Method to email the Report
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("api/Document/EmailReport/")]
public HttpResponseMessage EmailFarmFeatures([FromBody]MailMessage email)
{
return Request.CreateResponse(HttpStatusCode.OK);
}
I am attempting to call this WebAPI from MVC Method as below:
private void EmailReport(string reportName, byte[] bytes)
{
ContentType ct = new ContentType(MediaTypeNames.Application.Octet);
var attachments = new List<Attachment>();
var attach = new Attachment(new MemoryStream(bytes), ct);
attach.ContentDisposition.FileName = reportName;
attachments.Add(attach);
string strFrom = ConfigurationManager.AppSettings["FromEmail"];
string strTo = ConfigurationManager.AppSettings["ToEmail"];
string subject = string.Format("Customer Report - {0}", customerId);
string body = string.Format("Report for Customer {0} attached.", customerId);
string mailServer = ConfigurationManager.AppSettings["SmtpServer"];
MailMessage message = EmailHelper.CreateMailMessage(strFrom, strTo, "", "", subject, body, attachments, mailServer, false);
using (var client = new HttpClient())
{
var requestBody = JsonConvert.SerializeObject(message);
var postRequest = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = client.PostAsync("http://localhost/myWS/api/Document/EmailReport/", postRequest).GetAwaiter().GetResult();
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception("Error occured emailing report");
}
}
}
I am currently getting an error on this line:
var requestBody = JsonConvert.SerializeObject(message);
[InvalidOperationException: Timeouts are not supported on this stream.]
System.IO.Stream.get_ReadTimeout() +57
GetReadTimeout(Object ) +81
Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) +114
[JsonSerializationException: Error getting value from 'ReadTimeout' on 'System.IO.MemoryStream'.]
Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) +274
I believe it is something to do with attemptiong to seriliaze the memory stream attachment though I am not sure what the fix is to make sure this attachment gets included on the POST Request to the API Method
MailMessage isn't Serializable Just create a Separate regular object which represents a mail message.
Have a look at this Thread I guess it's pretty much what you need:
(https://discuss.hangfire.io/t/help-sending-email-mailmessage-deserialize-problem/354/5)[https://discuss.hangfire.io/t/help-sending-email-mailmessage-deserialize-problem/354/5]
Related
I am trying to send the same automatic email to multiple email addresses but I can't get it to work.
[HttpGet("largeorderemail")]
public IActionResult LargeOrderEmail()
{
try
{
//var bodyString = $"<h3>{msg}</h3><br/><p> Visit the site <a href='{Startup.appSettings.AllowOrigin}/lidarweb'> LiDAR GIS portal.</a></p>";
var bodyString = $"<h3>email body</h3>" +
<br/>" +
var emailService = new Email { To = "info#tel.net" };
var response = emailService.ExecuteLargeOrder(bodyString);
return Ok();
}
catch (Exception e)
{
Log.Error(e);
return NotFound();
}
}
public async Task<Response> ExecuteLargeOrder(string bodyString)
{
var fromAddr = new EmailAddress(from, "Info");
subject = "large order";
var toAddr = new EmailAddress(to, "User");
plainTextContent = "";
htmlContent = bodyString;
var msg = MailHelper.CreateSingleEmail(fromAddr, toAddr, subject, plainTextContent, htmlContent);
var response = await client.SendEmailAsync(msg);
return response;
}
When I send an email to a single address, it works. Like so: var emailService = new Email { To = "info#tel.net" };
but when I try something like this, it doesn't send the email var emailService = new Email { To = "info#tel.net, info#gmail.com" };
I also tried separating the address like so var emailService = new Email { To = "info#tel.net; info#gmail.com" }; but this also doesn't work.
Any suggestions?
Instead of putting Email addresses, try doing this way. Keep all your Email address in Array and try looping through the Array so that you can achieve your goal.
i am trying to accept a photo as an attachment in Microsoft chat-bot waterFall Dialog...then sending it as an attachment or (even in the body) of an email functionality (which i created)..
the email functionality seems to be working....however i am unable to pass the photo attachment in the email
it is like:
cannot convert from microsoft bot schema attachment to string
this is my code : the first method is to ask user to upload photo
private static async Task<DialogTurnResult> UploadAttachmentAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["desc"] = (string)stepContext.Result;
if (lang == "en")
{
lang = "en";
return await stepContext.PromptAsync(
attachmentPromptId,
new PromptOptions
{
Prompt = MessageFactory.Text($"Can you upload a ScreenShot of the Error?"),
});
}
else if (lang == "ar")
{
lang = "ar";
return await stepContext.PromptAsync(
attachmentPromptId,
new PromptOptions
{
Prompt = MessageFactory.Text($"هل يمكنك تحميل لقطة شاشة للخطأ؟"),
});
}
else return await stepContext.NextAsync();
}
the second method is the upload code itself:
private async Task<DialogTurnResult> UploadCodeAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
List<Attachment> attachments = (List<Attachment>)stepContext.Result;
string replyText = string.Empty;
foreach (var file in attachments)
{
// Determine where the file is hosted.
var remoteFileUrl = file.ContentUrl;
// Save the attachment to the system temp directory.
var localFileName = Path.Combine(Path.GetTempPath(), file.Name);
// Download the actual attachment
using (var webClient = new WebClient())
{
webClient.DownloadFile(remoteFileUrl, localFileName);
}
replyText += $"Attachment \"{file.Name}\"" +
$" has been received and saved to \"{localFileName}\"\r\n";
}
return await stepContext.NextAsync();
}
and the third is to store the photo as activity result to pass it later
private static async Task<DialogTurnResult> ProcessImageStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["picture"] = ((IList<Attachment>)stepContext.Result)?.FirstOrDefault();
await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Attachment Recieved...Thank you!!") }, cancellationToken);
return await stepContext.EndDialogAsync();
}
and finally the step where i am storing the values i got from each stepcontext and should be passed in an email body: (the attachment is supposed to be stoted in ticketProfile.screenShot)
private static async Task<DialogTurnResult> SummaryStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var ticketProfile = await _ticketDialogAccessor.GetAsync(stepContext.Context, () => new Ticket(), cancellationToken);
ticketProfile.userType = (string)stepContext.Values["userType"];
ticketProfile.staffType = (string)stepContext.Values["staffType"];
ticketProfile.empIdInfo = (string)stepContext.Values["shareId"];
ticketProfile.emailInfo = (string)stepContext.Values["shareEmail"];
ticketProfile.helpType = (string)stepContext.Values["helpType"];
ticketProfile.describeHelp = (string)stepContext.Values["desc"];
ticketProfile.screenShot = (Attachment)stepContext.Values["picture"];
string[] paths = { ".", "adaptiveCard.json" };
var cardJsonObject = JObject.Parse(File.ReadAllText(Path.Combine(paths)));
var userEmailValue = cardJsonObject.SelectToken("body[2].facts[0]");
var userIdValue = cardJsonObject.SelectToken("body[2].facts[1]");
var userTypeValue = cardJsonObject.SelectToken("body[2].facts[2]");
var staffTypeValue = cardJsonObject.SelectToken("body[2].facts[3]");
var helpTypeValue = cardJsonObject.SelectToken("body[2].facts[4]");
var describeValue = cardJsonObject.SelectToken("body[2].facts[5]");
userEmailValue["value"] = ticketProfile.emailInfo;
userIdValue["value"] = ticketProfile.empIdInfo;
userTypeValue["value"] = ticketProfile.userType;
staffTypeValue["value"] = ticketProfile.staffType;
helpTypeValue["value"] = ticketProfile.helpType;
describeValue["value"] = ticketProfile.describeHelp;
var attachment = new Attachment()
{
Content = cardJsonObject,
ContentType = "application/vnd.microsoft.card.adaptive"
};
var reply = stepContext.Context.Activity.CreateReply();
reply.Attachments = new List<Attachment>();
reply.Attachments.Add(attachment);
await stepContext.Context.SendActivityAsync(reply);
Email($"Here you go{Environment.NewLine}{ticketProfile.screenShot}");
return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
}
the email function:
public static void Email(string htmlString)
{
try
{
MailMessage mail = new MailMessage();
SmtpClient SmtpServer = new SmtpClient();
mail.From = new MailAddress("hassanjarko55#gmail.com");
mail.Subject = "New Ticket";
mail.Body = htmlString;
SmtpServer.Port = 587;
SmtpServer.Host = "smtp.gmail.com";
SmtpServer.EnableSsl = true;
SmtpServer.UseDefaultCredentials = false;
SmtpServer.Credentials = new NetworkCredential("user Name, "password");
SmtpServer.DeliveryMethod = SmtpDeliveryMethod.Network;
mail.To.Add(new MailAddress("hassan.jarko#yahoo.com"));
mail.IsBodyHtml = true;
SmtpServer.Send(mail);
}
catch (Exception e)
{
e.ToString();
}
}
public class Ticket
{
public string userType { get; set; }
public string staffType { get; set; }
public string helpType { get; set; }
public string helpWith { get; set; }
public string describeHelp { get; set; }
public Attachment screenShot { get; set; }
public string emailInfo { get; set; }
public string empIdInfo { get; set; }
}
any help will be much appreciated...thanks in advance
thanks a lot for #Alphonso...appreciate your efforts to hep...
i did the following to send the picture received from my chatbot as attachment as an email:
1-moved my email functionality method inside SummaryStepAsync method.
2-downloaded the image accepted from user using WebClient
string contentURL = ticketProfile.screenShot.ContentUrl;
string name = ticketProfile.screenShot.Name;
using (var client = new WebClient())
{
client.DownloadFile(contentURL, name);
client.DownloadData(contentURL);
client.DownloadString(contentURL);
}
3-passed it to my email functionality
try
{
HttpClient httpClient = new HttpClient();
//Help Desk Email Settings
MailMessage helpDeskMail = new MailMessage();
if (ticketProfile.screenShot != null)
{
System.Net.Mail.Attachment data = new System.Net.Mail.Attachment(ticketProfile.screenShot.Name);
helpDeskMail.Attachments.Add(data);
}
that's it :)
Have you tried attaching the file name instead of attaching a microsoft.bot.schema.attachment type
also have a look # this it might help you
How do I add an attachment to an email using System.Net.Mail?
Also also in you email function you need to add this code in order to have an attachment in your email
mail.Attachments.Add(new Attachment());
Note: I don't have that big knowledge in C# but I like to participate in these type of questions that have no answers to help the future programmers
After successfully sending email with attachment I have to delete files I've sent as attachement.
Files are in use so I have an exception.
I've used the code of the documentation. I'm using a method to create and send the email so everything is disposed automatically after calling it.
MimeMessage eMail = new MimeMessage();
eMail.From.Add (new MailboxAddress(fromDescription, fromAddress));
foreach (string to in toAddress)
eMail.To.Add(new MailboxAddress(to));
if (ccAddress != null)
foreach (string cc in ccAddress)
eMail.Cc.Add(new MailboxAddress(cc));
if (ccnAddress != null)
foreach (string ccn in ccnAddress)
eMail.Bcc.Add(new MailboxAddress(ccn));
eMail.Subject = subject;
var Body = new TextPart("plain")
{
Text = body
};
// now create the multipart/mixed container to hold the message text and the attachment
var multipart = new Multipart("mixed");
multipart.Add(Body);
if (attachments != null)
{
foreach (string attachmentPath in attachments)
{
// create an attachment for the file located at path
var attachment = new MimePart(MimeTypes.GetMimeType(attachmentPath))
{
Content = new MimeContent(File.OpenRead(attachmentPath), ContentEncoding.Default),
ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
ContentTransferEncoding = ContentEncoding.Base64,
FileName = Path.GetFileName(attachmentPath)
};
multipart.Add(attachment);
}
}
// now set the multipart/mixed as the message body
eMail.Body = multipart;
using (var client = new SmtpClient())
{
// For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS)
//client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect(SmtpHost, SmtpPort, SecureSocketOptions.SslOnConnect);
// Note: since we don't have an OAuth2 token, disable
// the XOAUTH2 authentication mechanism.
//client.AuthenticationMechanisms.Remove("XOAUTH2");
// Note: only needed if the SMTP server requires authentication
client.Authenticate(SmtpUser, SmtpPassword);
client.Send(eMail);
client.Disconnect(true);
}
What's wrong? Anyoone could help me?
Thank you
You need to dispose the stream you opened for the attachment:
File.OpenRead(attachmentPath)
You could do something like this:
var streams = new List<Stream> ();
if (attachments != null) {
foreach (string attachmentPath in attachments) {
// create an attachment for the file located at path
var stream = File.OpenRead(attachmentPath);
var attachment = new MimePart(MimeTypes.GetMimeType(attachmentPath)) {
Content = new MimeContent(stream, ContentEncoding.Default),
ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
ContentTransferEncoding = ContentEncoding.Base64,
FileName = Path.GetFileName(attachmentPath)
};
multipart.Add(attachment);
streams.Add (stream);
}
}
And then, after sending the message, do this:
foreach (var stream in streams)
stream.Dispose ();
I am sending an email from .net core application using MailKit, and it will sent it successfully.
But I want to use HTML template to send email with MailKit in .Net core.
Here are the code currently sending email with static body part
var emailMessage = new MimeMessage();
if (!string.IsNullOrWhiteSpace(cc))
{
emailMessage.Cc.Add(new MailboxAddress(cc));
}
else if (!string.IsNullOrWhiteSpace(EmailUserNameCC))
{
emailMessage.Cc.Add(new MailboxAddress(EmailUserNameCC));
}
if (!string.IsNullOrWhiteSpace(EmailUserNameBCC))
{
emailMessage.Bcc.Add(new MailboxAddress(EmailUserNameBCC));
}
emailMessage.From.Add(new MailboxAddress(mailFrom));
emailMessage.To.Add(new MailboxAddress(mailTo));
emailMessage.Subject = subject;
if (!string.IsNullOrWhiteSpace(replyTo))
{
emailMessage.InReplyTo = replyTo;
}
var builder = new BodyBuilder();// { TextBody = message };
builder.HtmlBody = message;
if (attachments != null && attachments.Count > 0)
{
foreach (var item in attachments)
{
builder.Attachments.Add(item.Key, item.Value);
}
builder.HtmlBody = builder.HtmlBody + " \n" + " PFA";
}
var multipart = new Multipart("mixed");
multipart.Add(new TextPart("html") { Text = message });
emailMessage.Body = builder.ToMessageBody();
using (var client = new SmtpClient())
{
var credentials = new NetworkCredential
{
UserName = EmailUserName,
Password = EmailPassword
};
if (!client.IsConnected)
{
client.Connect(SmtpHost, Convert.ToInt32(EmailHostPort));
client.Authenticate(EmailUserName, EmailPassword);
}
client.MessageSent += c_EmailReached;
client.Send(emailMessage);
}
Now, I want to use HTML template to replace body part.
So how can I use HTML Template with MailKit in .Net Core ?
Additional:
-> Also the special characters are not showing in actual email after sending email with html template. For some special characters it is displaying � . So how can I resolved this, to show special characters also.
Thanks.
You can use StreamReader to read the source file and assign it to your builder.HtmlBody.
using (StreamReader SourceReader = System.IO.File.OpenText(path to your file))
{
builder.HtmlBody = SourceReader.ReadToEnd();
}
I am using SendGrid mailhelper (as part of C# SDK) to send email. I need to send to multiple users, and hence I am using Personalization.
I get an error : Bad Request
This is my code:
static async Task Execute(string sub, string body, List<Recipient> recipients)
{
string apiKey = Environment.GetEnvironmentVariable("SendGrid_ApiKey", EnvironmentVariableTarget.User);
dynamic sg = new SendGridAPIClient(apiKey);
SendGrid.Helpers.Mail.Email from = new SendGrid.Helpers.Mail.Email("test1#gmail.com");
string subject = sub;
Personalization personalization = new Personalization();
SendGrid.Helpers.Mail.Email emails = new SendGrid.Helpers.Mail.Email();
var i = 0;
foreach (var recp in recipients)
{
emails.Address = recp.Email;
emails.Name = recp.FirstName + " " + recp.LastName;
personalization.AddTo(emails);
i++;
}
SendGrid.Helpers.Mail.Email to = new SendGrid.Helpers.Mail.Email("test1#gmail.com");
Content content = new Content("text/plain", body);
Mail mail = new Mail(from, subject, to, content);
mail.AddPersonalization(personalization);
dynamic response = await sg.client.mail.send.post(requestBody: mail.Get());
}
I appreciate if someone could advise me what am I doing incorrect.
Sendgrid API responds with bad request when there are more than 1 email address that is the same in the Personalization object. Make sure all the emails are unique