MVC Azure SendGrid - c#

I have a controller action method when triggered post data to the ForgotPassword method:
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
return View("ForgotPasswordConfirmation");
}
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here");
return RedirectToAction("ForgotPasswordConfirmation", "Account");
}
// If we got this far, something failed, redisplay form
return View(model);
}
web.config file
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="SendGridUsername" value="XXXXXXXXXXXXXXXXXXXXXX" />
<add key="SendGridPassword" value="XXXXXXXXXXXXXX" />
<add key="SendGridApiKey" value="XXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
</appSettings>
My IdentityConfig file looks like this:
public class EmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
await configSendGridasync(message);
}
// Use NuGet to install SendGrid (Basic C# client lib)
private async Task configSendGridasync(IdentityMessage message)
{
var myMessage = new SendGridMessage();
myMessage.AddTo(message.Destination);
myMessage.From = new System.Net.Mail.MailAddress(
"Joe#contoso.com", "Joe S.");
myMessage.Subject = message.Subject;
myMessage.Text = message.Body;
myMessage.Html = message.Body;
var credentials = new NetworkCredential(
ConfigurationManager.AppSettings["SendGridUsername"],
ConfigurationManager.AppSettings["SendGridPassword"]
);
// Create a Web transport for sending email.
var transportWeb = new Web(credentials);
// Send the email.
if (transportWeb != null)
{
await transportWeb.DeliverAsync(myMessage);
}
else
{
Trace.TraceError("Failed to create Web transport.");
await Task.FromResult(0);
}
}
}
However no email is sent , what am I doing wrong and how can I fix this as I have followed the instructions from Rick Andersons post on msdn.

You are using an outdated version of sendgrid C# SDK which points to V2 api. The current API version is V3. The document which you are following is not updated . I am currently in progress to update the document. You need to add the below namespace in your service -
using SendGrid;
using SendGrid.Helpers.Mail; //optional if you want to use the MailHelper class
And then use below code in your configSendGridasync method -
private async Task configSendGridasync(IdentityMessage message)
{
var apiKey = Convert.ToString(ConfigurationManager.AppSettings["SendGridApiKey"]);
var client = new SendGridClient(apiKey);
var myMessage = new SendGridMessage();
myMessage.AddTo(new EmailAddress(message.Destination));
myMessage.SetFrom(new EmailAddress("Joe#contoso.com", "Joe S."));
myMessage.SetSubject(message.Subject);
myMessage.AddContent(MimeType.Text, message.Body);
myMessage.AddContent(MimeType.Html, message.Body);
try
{
var response = await client.SendEmailAsync(msg);
}
catch(Exception err)
{
Trace.TraceError("Failed to create Web transport: ."+err.message);
await Task.FromResult(0);
}
}
You need to install Sendgrid package from nuget using the below command before writing the code -
Install-Package Sendgrid -Version 9.10.0
The full code is like below -
using SendGrid;
using SendGrid.Helpers.Mail;
public class EmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
await configSendGridasync(message);
}
// Use NuGet to install SendGrid (Basic C# client lib)
private async Task configSendGridasync(IdentityMessage message)
{
var apiKey = Convert.ToString(ConfigurationManager.AppSettings["SendGridApiKey"]);
var client = new SendGridClient(apiKey);
var myMessage = new SendGridMessage();
myMessage.AddTo(new EmailAddress(message.Destination));
myMessage.SetFrom(new EmailAddress("Joe#contoso.com", "Joe S."));
myMessage.SetSubject(message.Subject);
myMessage.AddContent(MimeType.Text, message.Body);
myMessage.AddContent(MimeType.Html, message.Body);
try
{
var response = await client.SendEmailAsync(msg);
}
catch(Exception err)
{
Trace.TraceError("Failed to create Web transport: ."+err.message);
await Task.FromResult(0);
}
}
}
Here is a link to example code :
https://github.com/sendgrid/sendgrid-csharp/blob/master/USE_CASES.md

Related

How to send an email to a relevant person using user input in the bot

I created a QnA bot. For that I added some questions and answers in QnA maker and am using it in my bot application.
If the user asks the question which is not existing in predefined questions, bot needs to get the unanswered question from the user. For that bot will ask the user's details like email id. Then bot needs to send email to the professional (bot already has the email id of him) and the content of the email should be unanswered question. Here I attached my code.
But I couldn't send the mail. After I enter the email id in emulator it says:
Exception: Failure sending mail.[File of type 'text/plain'].
So how can I send the mail to particular person from bot.
Code:
using System;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using System.Net;
using System.Net.Mail;
namespace QNA_Bot.Dialogs
{
[Serializable]
public class RootDialog : IDialog<object>
{
private static string unans;
public Task StartAsync(IDialogContext context)
{
context.Wait(MessageReceivedAsync);
return Task.CompletedTask;
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
unans = activity.Text;
// calculate something for us to return
var text = (activity.Text ?? string.Empty);
var url = "https://westus.api.cognitive.microsoft.com/qnamaker/v2.0/knowledgebases/b07f68a7-4a65-4330-8574-6529cf4c9391/generateAnswer";
var httpContent = new StringContent("{'question':'"+text+"'}",Encoding.UTF8,"application/json");
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "57feb2c9cd734fe48f624c4361dceb59");
var httpResponse = await httpClient.PostAsync(url, httpContent);
var httpResponseMessage = await httpResponse.Content.ReadAsStringAsync();
dynamic httpResponseJson = JsonConvert.DeserializeObject(httpResponseMessage);
var replyMessage = (string)httpResponseJson.answers[0].answer;
if(replyMessage== "No good match found in the KB")
{
await context.PostAsync("Sorry, I couldn't answer you...");
await context.PostAsync("I can contact a relevant person and let you know...");
await context.PostAsync("So could you give your mail id... If so type 'yes'");
context.Wait(GettingMailIdAsync);
}
else
{
await context.PostAsync(replyMessage);
context.Wait(MessageReceivedAsync);
}
}
private async Task GettingMailIdAsync(IDialogContext context,IAwaitable<object> result)
{
var activity = await result as Activity;
var ans = activity.Text;
if (ans == "yes")
{
await context.PostAsync("Type your Mail ID");
context.Wait(SendMailIdAsync);
}
}
private async Task SendMailIdAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
var mailId = activity.Text;
var fromAddress = new MailAddress("From#gmail.com", "From Name");
var ToAddress = new MailAddress("To#gmail.com", "To Name");
const string fromPassword = "Pass";
const string subject = "User_Question_From_ERPBOT";
string body = "This Question was asked by" + mailId + " \n " + unans + "If you know the answer, Please contact the person through " + mailId+"The following is the question"+unans;
var smtp = new SmtpClient
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
};
using (var message = new MailMessage(fromAddress, ToAddress)
{
Subject = subject,
Body = body
})
{
smtp.Send(message);
}
}
}
}
I try to reproduce the issue with the code that you provided, I test your code to send email using my gmail account, which works for me.
Failure sending mail.
To troubleshoot the issue, please try:
make sure you provide correct credentials (userName&password)
check if the port 587 is blocked
check if you turn on "Allow less secure apps"

Bot Framework - return Image

I use windows7 Professional and other Bot run without problem.
I want to return an image to my BOT, but the code suggested by Microsoft guide doesn't run
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity reply = activity.CreateReply( $" Hello");
reply.Attachments.Add(new Attachment()
{
ContentUrl = $"https://upload.wikimedia.org/wikipedia/en/a/a6/Bender_Rodriguez.png",
ContentType = "image/png",
Name = "Bender_Rodriguez.png"
});
await connector.Conversations.ReplyToActivityAsync(reply);
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
I tried this code with Bot Emulator and got the following error:
You need to initialize the Attachments array. In your code, it's null so the Add call is causing a NULL ref exception.
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity reply = activity.CreateReply($" Hello");
reply.Attachments = new List<Attachment>(); //****** INIT
reply.Attachments.Add(new Attachment()
{
ContentUrl = $"https://upload.wikimedia.org/wikipedia/en/a/a6/Bender_Rodriguez.png",
ContentType = "image/png",
Name = "Bender_Rodriguez.png"
});
await connector.Conversations.ReplyToActivityAsync(reply);
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
You have to add these lines of code after reply activity initialization.
reply.Attachments = new List<Attachment>();
reply.Recipient = activity.From;
reply.Type = "message";
You can refer this link for more details
downloading file (pdf/image) from using Microsoft bot framework

ASP.NEt Web API 2 SendEmailAsync not sending email?

I have the following code for my register method of my AccountController of my ASP.Net Web-API2 Applicaiton:
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// make sure token code is URLEncoded to make sure any special characters in code are allowed in URI to be created
//code = HttpUtility.UrlEncode(code);
//create the URL to be put into the email
var callbackUrl = new Uri(Url.Link("ConfirmEmailRoute", new { userId = user.Id, code = code }));
//create Email
string msgUserId = user.Id;
string msgSubject = "Home Turf Network - Confirm your account";
string msgBody = "Please confirm your Home Turf Network account by clicking here";
//send email
await UserManager.SendEmailAsync(msgUserId, msgSubject, msgBody);
return Ok();
//return CreatedAtRoute("DefaultApi", new { id = user.Id }, user);
}
It creates the user successfully, creates the code, callbackURL and from what I can tell everything that is needed for an email to go out to the registered user. But the Email never goes out....
I have tested the callbackUrl that gets created and it does register the email in the DB successfully after it is put into a browser. If the email would send out it would work perfectly.
I tried putting a breakpoint in my IdentityConfig where my EmailService gets set up and it never gets triggered when I debug the application and I can't figure out why it won't send out the email.
Here is my EmailService in my IdentityConfig.cs:
public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
//plug in your Email Service here to send an email
MailMessage msg = new MailMessage(ConfigurationManager.AppSettings["mailAccount"], message.Destination, message.Subject, message.Body);
msg.IsBodyHtml = true;
using (SmtpClient client = new SmtpClient("smtp.gmail.com"))
{
client.EnableSsl = true;
client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential( ConfigurationManager.AppSettings["mailAccount"], ConfigurationManager.AppSettings["mailPassword"] );
client.Port = 587;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Send(msg);
}
return Task.FromResult(0);
}
}
Any help tracing this issue out will be much appreciated.

UserManager.SendEmailAsync hangs

I have a custom user manager with a custom EmailService. I'm calling the UserManager.SendEmailAsync() method in the AccountController, and it just hangs. I even tried to use it with invalid SMTP hostname, then an exception occurs and in debug I can see it goes into the catch block, but regardless the return View(model) statement, it just "hangs" in the browser and keeps on loading forever.
Any ideas?
ApplicationUserManager constructor:
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
EmailService = new EmailService();
}
EmailService:
public class EmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
// Credentials:
string smtpServer = ConfigurationManager.AppSettings["EmailSmtpServer"];
int smtpPort = int.Parse(ConfigurationManager.AppSettings["EmailSmtpPort"]);
bool enableSsl = bool.Parse(ConfigurationManager.AppSettings["EmailEnableSSL"]);
string smtpUsername = ConfigurationManager.AppSettings["EmailSmtpUsername"];
string smtpPassword = ConfigurationManager.AppSettings["EmailSmtpPassword"];
string sentFrom = ConfigurationManager.AppSettings["EmailSentFrom"];
// Configure the client:
var client = new SmtpClient(smtpServer, Convert.ToInt32(587));
client.Port = smtpPort;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.EnableSsl = enableSsl;
// Create the credentials:
var credentials = new NetworkCredential(smtpUsername, smtpPassword);
client.Credentials = credentials;
// Create the message:
var mail = new System.Net.Mail.MailMessage(sentFrom, message.Destination);
mail.Subject = message.Subject;
mail.Body = message.Body;
// Send:
await client.SendMailAsync(mail);
}
}
ForgotPassword method in AccountController
//
// POST: /Account/ForgotPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
// Don't check confirmation status for now
//if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
if (user == null)
{
ModelState.AddModelError("", "The user either does not exist or is not confirmed.");
return View();
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
try
{
await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here");
}
catch (Exception ex)
{
ModelState.AddModelError("", ex.Message);
return View(model);
}
return RedirectToAction("ForgotPasswordConfirmation", "Account");
}
// If we got this far, something failed, redisplay form
return View(model);
}
This Works for me
ApplicationUserManager constructor:
public AppUserManager(IUserStore<AppUser> store)
: base(store)
{
this.UserTokenProvider = new TotpSecurityStampBasedTokenProvider<AppUser, string>();
this.EmailService = new EmailService();
}
EmailService:
public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
// Credentials:
var credentialUserName = ConfigurationManager.AppSettings["emailFrom"];
var sentFrom = ConfigurationManager.AppSettings["emailFrom"];
var pwd = ConfigurationManager.AppSettings["emailPassword"];
// Configure the client:
System.Net.Mail.SmtpClient client =
new System.Net.Mail.SmtpClient("smtp-mail.outlook.com");
client.Port = 587;
client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
// Create the credentials:
System.Net.NetworkCredential credentials =
new System.Net.NetworkCredential(credentialUserName, pwd);
client.EnableSsl = true;
client.Credentials = credentials;
// Create the message:
var mail =
new System.Net.Mail.MailMessage(sentFrom, message.Destination);
mail.Subject = message.Subject;
mail.Body = message.Body;
// Send:
return client.SendMailAsync(mail);
}
}
IMPORTANT If you are using external mail provider you should revise your external applications configurations for example:
gmail : Allowing less secure apps to access your account
ForgotPassword method in AccountController
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> RecoveryPassword(LoginInfoModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
return View("ForgotPasswordConfirmation");
}
var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account",
new { UserId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Reset Password",
"Reinicia tu contraseƱa clicando : aqui");
return View("ForgotPasswordConfirmation");
}
// If we got this far, something failed, redisplay form
return View(model);
}
And finally I see my e-mail on my mailbox

Web API POST MultipartFormDataContent: Can response return multipartform content?

I am trying to send one or more files (.doc) to an ASP.NET Web API 2 service and return a modified version (.docx). I am able to send the file and get a response but the HttpContentMultipartExtensions that I used within the service on the HTTPContent in the request are not available back in the client to use on the response. Is this something that isn't available out of the box that can be wired up, or is this a misuse of multipartform?
There are two apps: the MVC client and Web API service:
Controller for Client (reads sample files from App_Data, POST to serviceserver/api/mpformdata):
public async Task<ActionResult> PostMpFormData()
{
DirectoryInfo dir = new DirectoryInfo(Server.MapPath(#"~\App_Data"));
var files = dir.GetFiles().ToList();
using (HttpClient client = new HttpClient())
{
HttpResponseMessage result = new HttpResponseMessage();
using (MultipartFormDataContent mpfdc = new MultipartFormDataContent())
{
foreach (var file in files)
{
mpfdc.Add(new StreamContent(file.OpenRead()), "File", file.Name);
}
var requestUri = ConfigurationManager.AppSettings["DocumentConverterUrl"] + "/api/mpformdata";
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("multipart/form-data"));
result = client.PostAsync(requestUri, mpfdc).Result;
}
ViewBag.ResultStatusCode = result.StatusCode;
ViewBag.ContentLength = result.Content.Headers.ContentLength;
// Fiddler show that it returns multipartform content, but how do I use it?
// var resultContent = result.Content;
}
return View();
}
Controller for Web API service:
public class UploadController : ApiController
{
[HttpPost, Route("api/mpformdata")]
public async Task<HttpResponseMessage> PostMpFormData()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
return await UseMultipartFormDataStream();
}
private async Task<HttpResponseMessage> UseMultipartFormDataStream()
{
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
MultipartFormDataContent mpfdc = new MultipartFormDataContent();
try
{
await Request.Content.ReadAsMultipartAsync(provider);
foreach (MultipartFileData file in provider.FileData)
{
var filename = file.Headers.ContentDisposition.FileName;
Trace.WriteLine(filename);
Trace.WriteLine("Server file path: " + file.LocalFileName);
mpfdc.Add(new ByteArrayContent(File.ReadAllBytes(file.LocalFileName)), "File", filename);
}
var response = Request.CreateResponse();
response.Content = mpfdc;
response.StatusCode = HttpStatusCode.OK;
return response;
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
Multipart extensions are part of System.Net.Http.Formatting dll. Make sure you have the nuget package Microsoft.AspNet.WebApi.Client installed at your client.

Categories