Getting SendGrid Server Results in ASP.Net Core - asp.net-core

Here's my code to send email via SendGrid.
public Task<Result> Execute(string apiKey, string subject, string message, string email)
{
var client = new SendGridClient(apiKey);
string senderEmail = this.Configuration["Email:Address"];
string senderName = this.Configuration["Email:Name"];
var msg = new SendGridMessage()
{
From = new EmailAddress(senderEmail, senderName),
Subject = subject,
PlainTextContent = message,
HtmlContent = message
};
msg.AddTo(new EmailAddress(email));
var response = client.SendEmailAsync(msg);
return response;
}
It is able to send email confirmation and password reset emails, when invoked by ASP.Net Core Identity code.
However, when I try to send email using my own controller action (for a Contact Us feature), nothing happens.
This is the controller action.
public async Task<JsonResult> SendContactEmail(int id, string message)
{
Page page = await this.Get(id);
var result = _emailSender.SendEmailAsync(page.Email, page.Subject, message);
return new JsonResult(result);
}
Is there a way to troubleshoot this? I don't get any exceptions and the response object doesn't seem to have any useful property like a message from the SendGrid server.
UPDATE:
SendGrid's API does return an informative result. I have updated my code to return this.
https://github.com/sendgrid/sendgrid-csharp/blob/master/src/SendGrid/Response.cs

Related

How do I populate IUrlHelper from a Background Quartz Task for Email Confirmation?

How do I populate IUrlHelper from a Background Quartz Task for Email Confirmation?
I am using Radzen Studio to create a custom website. It has automatically generated code for an Account Management Controller (AccountController.cs).
I would prefer to call the "SendConfirmationEmail" method from the Background Task (Quartz) to send the Client an Email when their account is created (within the Background Task).
I have not been able to find a good solution for populating the parameter "IUrlHelper url". Here's a copy of the SendConfirmationEmail Method:
public async Task SendConfirmationEmail(UserManager<ApplicationUser> userManager, ApplicationUser user, IUrlHelper url, string scheme)
{
var code = await userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: scheme);
//
// Author: Richard
// Date: 09/27/2022
// Reason: To import an EmailTemplate for Portal Invitation
//
var EmailTemplate = portalDbService.GetEmailTemplateByAppLink("PortalInvite");
string Body = EmailTemplate.Result.Body;
string EmailBody = Body.Replace("{CLIENTNAME}", user.Email);
string EmailSubject = EmailTemplate.Result.Subject;
await SendEmail(user, code, callbackUrl, EmailSubject, EmailBody, true);
}
Thanks in Advance,
Richard

Sending mail multiple times by Microsoft Graph

Blazor server application
I have a web appliction that is using AzureAd and OpenIdConnect to login to this application.
I am sending mail by using Microsoft graph and I am using the example in Microsoft doc with some changes like this:
#inject Microsoft.Graph.GraphServiceClient GraphServiceClient
#inject MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler
var message = new Message
{
Subject = "Meet for lunch?",
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = "The new cafeteria is open."
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "fannyd#contoso.onmicrosoft.com"
}
}
},
CcRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "danas#contoso.onmicrosoft.com"
}
}
}
};
var saveToSentItems = false;
try
{
await GraphServiceClient.Me
.SendMail(message,saveToSentItems)
.Request()
.PostAsync();
}
catch(Exception ex)
{
ConsentHandler.HandleException(ex);
}
Scenario of the error
This works perfect but just for one time , if I try to send the same email again it doesn't work and I got no error but just redirect me to empty page.
If I logout and login again, then it works fine.
The error that I got in the second time:
Message = "IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent. "
MsalUiRequiredException = {"No account or login hint was passed to the AcquireTokenSilent call. "}
My Question
How can fix the code up to send multi emails?. I think that I have a problem with token but I don't know where should I start?.
Thanks
Add the other catch block to retrieve the specific issue if we have any related to permissions or other ServiceExceptions.
try
{
SendMail(); // Sending mail code here.
}
catch (Microsoft.Graph.ServiceException e)
{
// get the error here if we have any.
}
After some search, I think that I have to move the the permission Delegated permissions to Application Permissions like this:
Why should I use application permission?
In my case the user logged in for the first time and clicked on the button then the email will be send, but in the second time the application has to communicate with API graph without interaction from the user, that means without user and this exactly what I need(application permission).
I adjust the code like the following:
Client credentials provider:
The client credential flow enables service applications to run without user interaction. Access is based on the identity of the application. this is from Microsoft doc
private GraphServiceClient CreateGraphServiceClient()
{
// The client credentials flow requires that you request the
// /.default scope, and preconfigure your permissions on the
// app registration in Azure. An administrator must grant consent
// to those permissions beforehand.
var scopes = new[] { "https://graph.microsoft.com/.default" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";
// Values from app registration
var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
return new GraphServiceClient(clientSecretCredential, scopes);
}
Send mail with UserId, you can see the code in Microsoft doc:
puplic SendMyEmail()
{
GraphServiceClient graphClient = CreateGraphServiceClient;
var message = new Message
{
Subject = "Meet for lunch?",
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = "The new cafeteria is open."
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "fannyd#contoso.onmicrosoft.com"
}
}
},
CcRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "danas#contoso.onmicrosoft.com"
}
}
}
};
var saveToSentItems = false;
//See GetUserId down
string userId = await GetUserId();
await graphClient.Users[UserId]
.SendMail(message,saveToSentItems)
.Request()
.PostAsync();
}
}
UserId:
To get user Id you need AuthenticationStateProvider, this has to inject in the service of your application and then add to the constructor of your class, then you can use it.
puplic class MyClass
{
private readonly MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler;
private readonly AuthenticationStateProvider authenticationState;
puplic MyClass(
MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler,
AuthenticationStateProvider authenticationState)
{
this.authenticationState = authenticationState;
this.ConsentHandler = ConsentHandler;
}
public async Task<string> GetUserId()
{
var authSate = await authenticationState.GetAuthenticationStateAsync();
return authSate.User.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier");
}
//Here your
private GraphServiceClient CreateGraphServiceClient() { ...}
puplic SendMyEmail() {....}
}

cant send message to specific user. connection.on not being reached

I cant seem to reach the client from the hub. All I have is a .on on the client side and I am just trying to reach a break point but its never being reached. I have others on the client side I can reach without issue. I am not receiving any errors and not seeing any script issues in the dev tools console. All I want to do is fire off an action to a specific user. I have tried using both .Client and .User with the same result
On my client I have
connection.on("SendRequest", function (requestmessage) {
var whatever = requestmessage;
});
then in the hub
public async Task RequestPrivateChat(string UserListJS)
{
var ConnectionID = "";
MyUser user = new MyUser();
string message = "This is my message";
dynamic UserList = JsonConvert.DeserializeObject(UserListJS);
foreach (string item in UserList)
{
//I get the user okay then use the user.id below
user = _db.Users.Where(x => x.UserName == item).FirstOrDefault();
//I get the connection ID okay
ConnectionID = _connections.GetConnections(item).First();
//Both of these are reached but the client is never reached out to. Both Connection ID and user.Id are populated correctly
await Clients.Client(ConnectionID).SendAsync("SendRequest", message);
await Clients.User(user.Id.ToString()).SendAsync("SendRequest", message);
}
}
This for sending messages to all clients works fine
Hub
await Clients.All.SendAsync("ReceiveMessage", name, message);
Client
connection.on("ReceiveMessage", function (user, message) {
var msg = message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
var encodedMsg = user + " says " + msg;
var li = document.createElement("li");
li.textContent = encodedMsg;
document.getElementById("messagesList").appendChild(li);
});
UPDATE
I have tried moving this outside of visual studio into IIS just in case this was and IDE issue with same result. I also tried the following
await Clients.User("username").SendAsync("SendChatRequest", message);
and it still didn't work but oddly enough I realized when I first go to the hub
connection.on("SendRequest", function (requestmessage)
is being hit without ever being called. I have confirmed there are only 2 references to send request, one in the hub and one on the client. I am sure there is something I am missing.
Since your await this.Clients.All.SendAsync("SendRequest", message); works, you not passing correctly the connectionId to target the user.
What I suggest is:
Get the connection Id from the context like:
await Clients.Client(this.Context.ConnectionId).SendAsync("SendRequest", message);
Get the connection Id from the caller:
await Clients.Caller(this.Context.ConnectionId).SendAsync("SendRequest", message);
Add the client to specific group and call the method for the group (assuming you added the connection in to a group):
await Clients.Group("GroupName").SendAsync("SendRequest", message);

using Revalee.client to send email at background

Where should I call the revalee method to send mail email at background? What I am trying to achieve is to send email to the client if the expiration date is coming. I have follow the link: http://www.codeproject.com/Articles/738753/Scheduling-tasks-with-Revalee-and-MVC
My actionmethod is as follows:
public ActionResult SendExpirationMessage(int VehicleID)
{
// Validate the incoming request to ensure that this web app requested this callback
if (!RevaleeRegistrar.ValidateCallback(this.Request))
{
// Return a '401 Unauthorized' response to the Revalee service if the callback doesn't validate
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
}
ApplicationDbContext db = new ApplicationDbContext();
var user = db.UserVehicleViewModels.Find(VehicleID);
var span = user.TaxDate.AddYears(1).Subtract(DateTime.Now);
int days = span.Days;
if (days >= 7)
{
System.Net.Mail.MailMessage m = new System.Net.Mail.MailMessage(
new System.Net.Mail.MailAddress("abc#abc.com", "Web Registration"),
new System.Net.Mail.MailAddress(user.Email));
m.Subject = "Tax Notification";
m.Body = string.Format("Dear {0} <BR/>This is an email to notify you about the due tax date of your vehicle, please pay tax on time. Thank you\" title=\"User Email Confirm\"></a>",
user.UserName);
m.IsBodyHtml = true;
System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient("smtp.gmail.com");
smtp.Credentials = new System.Net.NetworkCredential("abc#abc.com", "password");
smtp.EnableSsl = true;
smtp.Send(m);
}
the helper method is:
private void ScheduleExpirationMessage(int VehicleID)
{
// The server address where the Revalee service is installed
string revaleeServiceHost = "192.168.1.4";
// The callback will occur 27 days from now
DateTimeOffset callbackTime = DateTimeOffset.Now.AddMinutes(1.0);
// The url that will be called back, including userId
Uri callbackUrl = new Uri(
string.Format("http://localhost/UserVehicle/SendExpirationMessage/{0}", VehicleID));
// Register the callback request with the Revalee service
RevaleeRegistrar.ScheduleCallback(revaleeServiceHost, callbackTime, callbackUrl);
}

Blank Message in Push Notification to Android Device Using GCM and Asp.net MVC Web API

I am using Asp.net MVC 4 Web API as a third party server to Push Notification for Android Device using GCM. It's working fine notification are being generated but the message is blank. I have spent whole day on it but could not find any solution please help me
Web API Function to Send Push Notification is as follows:
public Notification PushToAndroidDevice(string registrationid,string message)
{
Notification notification = new Notification();
try
{
var applicationID = "MY_APPLICATION_ID";
var SENDER_ID = "MY_SENDER_ID";
WebRequest tRequest;
tRequest = WebRequest.Create("https://android.googleapis.com/gcm/send");
tRequest.Method = "post";
tRequest.ContentType = "application/x-www-form-urlencoded";
tRequest.Headers.Add(string.Format("Authorization: key={0}", applicationID));
tRequest.Headers.Add(string.Format("Sender: id={0}", SENDER_ID));
string postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message=" + message + "&data.time=" + System.DateTime.Now.ToString() + "&registration_id=" + registrationid + "";
Byte[] byteArray = Encoding.UTF8.GetBytes(postData);
tRequest.ContentLength = byteArray.Length;
Stream dataStream = tRequest.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
WebResponse tResponse = tRequest.GetResponse();
dataStream = tResponse.GetResponseStream();
StreamReader tReader = new StreamReader(dataStream);
String sResponseFromServer = tReader.ReadToEnd();
notification.Message = sResponseFromServer;
tReader.Close();
dataStream.Close();
tResponse.Close();
notification.Status = true;
}
catch (Exception ex)
{
notification.Status = false;
notification.Message = "ERROR DESCRIPTION : " + ex.Message;
}
return notification;
}
Notification is a class having two properties Status bool and Message string
public class Notification
{
public bool Status { get; set; }
public string Message { get; set; }
}
By this code I'm able to send notification message on android mobile but the notification is blank please help me out ...........
You shuould check the MSGReceiver and MSGSerice (or corresponding) class that receives the message from GCM server.
You check print and see if you are receiving null. May be the variable names used there and the one you are sending from your MVC are different. This is a very short answer. If you have further question or difficulty in undestanding then please provide relevant code and filenames.