How do I create a webhook in ASP.NET MVC? - c#

I'm trying to create a simple webhook to receive a delivery receipt from Nexmo SMS service. The only documentation on their website was this.
During account set-up, you will be asked to supply Nexmo a CallBack URL for Delivery Receipt to which we will send a delivery receipt for each of your SMS submissions. This will confirm whether your message reached the recipient's handset. The request parameters are sent via a GET (default) to your Callback URL and Nexmo will be expecting response 200 OK response, or it will keep retrying until the Delivery Receipt expires (up to 72 hours).
I've been searching for ways to do this, and so far I have this method from an example I found online, although I'm not sure if this is correct. Anyways, this is being run on ASP.NET and on port 6563, so is this the port I'm supposed to be listening to? I downloaded an application called ngrok which should expose my local web server to the internet, so I ran the application and instructed it to listen onto port 6563, but no luck. I've been fiddling with it trying to find someway to post to this function.
[HttpPost]
public ActionResult CallbackURL()
{
System.IO.StreamReader reader = new System.IO.StreamReader(HttpContext.Request.InputStream);
string rawSendGridJSON = reader.ReadToEnd();
return new HttpStatusCodeResult(200);
}
Usually I can call the function directly to return the view just by visiting http://localhost:6563/Home/Index/CallbackURL
So I've inserted a breakpoint on the method signature, but it'll only get called if I remove the [HttpPost] from it. Any next steps that I should try?

First you have to remove the [HttpPost] bit because it clearly states that "parameters are sent via a GET".
Then you should also remove the return HttpStatusCodeResult(200) as it will return the 200 OK status code anyway if no error occures.
Then you should simply read the values from querystring or using model binding. Here is a sample:
public string CallbackURL()
{
string vals = "";
// get all the sent data
foreach (String key in Request.QueryString.AllKeys)
vals += key + ": " + Request.QueryString[key] + Environment.NewLine;
// send all received data to email or use other logging mechanism
// make sure you have the host correctly setup in web.config
SmtpClient smptClient = new SmtpClient();
MailMessage mailMessage = new MailMessage();
mailMessage.To.Add("...#...com");
mailMessage.From = new MailAddress("..#....com");
mailMessage.Subject = "callback received";
mailMessage.Body = "Received data: " + Environment.NewLine + vals;
mailMessage.IsBodyHtml = false;
smptClient.Send(mailMessage);
// TODO: process data (save to database?)
// disaplay the data (for degugging purposes only - to be removed)
return vals.Replace(Environment.NewLine, "<br />");
}

Before couple of weeks Asp.Net team has announced to support Web Hooks with Visual Studio.
Please have a look here for more detailed information:
https://neelbhatt40.wordpress.com/2015/10/14/webhooks-in-asp-net-a-visual-studio-extension/

Microsoft is working on ASP.NET WebHooks, a new addition to the ASP.NET family. It supports a lightweight HTTP pattern providing a simple pub/sub model for wiring together Web APIs and SaaS services.
See Introducing Microsoft ASP.NET WebHooks Preview

So the issue I was having wasn't with my webhook at all, it was actually with IIS Express. Apparently it blocks most traffic from foreign hosts so there is some tweaking you can do before tunneling anything to your server. If you follow these guides you should have a working server.
https://gist.github.com/nsbingham/9548754
https://www.twilio.com/blog/2014/03/configure-windows-for-local-webhook-testing-using-ngrok.html

Related

Blazor client side send an email

I included a contact form in a razor page, so an user can fill it with his email, a subject and a body. When he submit it, the email is send to my email adress.
My code looks like this example
But when i submit my form, i had this error
Operation is not supported on this platform.
It's not supported because i'm running it on the browser (client side).
I would like to know if someone as a turnaround for this case, without using a smtp server (since the user can access the credentials of the server) or
test#example.com
Thank you.
Regards, Samih.
This is not possible, because browsers have security restrictions which forbids sending E-Mails. This restrictions doesn't come from Blazor or ASP.NET Core. It won't work with JavaScript either. Or at least not with questionable hacks.
I won't recommend to use projects like smtp.js which are trying to work around those limitations: They're doing the only suiteable method by using a server-side API. But the problem here is, that you expose those credentials at least to smtp.js cause by generating a security token, they store your credentials on their servers so the API could fetch them when you call their Email.send() method from JS.
To realize this securely, you need some kind of API on the server side for sending those mails using a mailserver (mostly with SMTP). Since you say it runs on the browser, I'm assuming that you're using Blazor WebAssembly. So either create an API project which could be called using e.g. Ajax from your WASM project or switch to Blazor Server which allows you to run the code directly on the server, if this is suiteable for the use-case.
Important: Keep an eye on misuse!
Even with your own API using credentials stored secretly on your own server, it's important to prevent misuse. If there is an API that could send Mails to anyone with your account without any limitations, it will be only a matter of time until bots will abuse them to send spam - even when the credentials are not exposed!
This can harm your on many ways:
Spam or even malicious content in your name
Your mail account got taken down
Desired mails won't be send cause your mail is on every spam-list
...
For that reasons it should be in your interest to send mails only from your servers with proper limits on that API like allowing only whitelisting senders, rate limits and so on.
This blog post may be helpful to you: Blazor (Wasm) – How to Send Email from a PWA. It invokes the user's native mail application instead of relying on a server-based or API-based implementation.
Excerpted, "...for very basic email needs is to leverage the old-school technique of using “mailto:” anchor links combined with injecting Blazor’s IJSRuntime."
protected void SendLocalEmail(string toEmailAddress, string subject, string body)
{
JsRuntime.InvokeAsync<object>("blazorExtensions.SendLocalEmail",
new object[] { toEmailAddress, subject, body });
}
Then, in your wwwroot folder, you should have a corresponding .js file (i.e. GlobalFunctions.js) that contains the corresponding JavaScript SendLocalEmail() function
window.blazorExtensions = {
SendLocalEmail: function (mailto, subject, body) {
var link = document.createElement('a');
var uri = "mailto:" + mailto + "?";
if (!isEmpty(subject)) {
uri = uri + "subject=" + subject;
}
if (!isEmpty(body)) {
if (!isEmpty(subject)) { // We already appended one querystring parameter, add the '&' separator
uri = uri + "&"
}
uri = uri + "body=" + body;
}
uri = encodeURI(uri);
uri = uri.substring(0, 2000); // Avoid exceeding querystring limits.
console.log('Clicking SendLocalEmail link:', uri);
link.href = uri;
document.body.appendChild(link); // Needed for Firefox
link.click();
document.body.removeChild(link);
}
};
function isEmpty(str) {
return (!str || str.length === 0);
}
Finally, be sure you include a reference to your .js file in the index.html file (also in the wwwroot folder):
<script src="GlobalFunctions.js"></script>
I place the above script reference below this line:
<script>navigator.serviceWorker.register('service-worker.js');</script>

CS0103: The name 'test' doesn't exist in the actual context

I'm coding a mobile app who should save some infos in a private remote database.
Of course, I can't access public websites of my enterprise to implement a webservice. On the other hand, we have a mailbox with a permanently activated macro who is able to activate another macro when it receives an email with a predefined subject. So, potentially, that 'robot' can save infos I want it to save.
I had to think at different solutions, I choosed one, but I am less and less sure of my choice.
Anyway, my mobile app is developed with Cordova and Ionic Framework. I didn't want to implement a plugin to open my user's mail client, I wanted my mail to be sent automatically.
Finally, I found SendGrid, I thought I could implement it directly in my mobile app, but I didn't make it (If somebody dit it, could you tell me so ? It could delete some steps in my app)
So I reflected about put a third actor in my process. PHP appeared as the best : I'm used to it, and I know we can easily send an email while the SMTP is defined ... It's too bad I can't implement webservices in public websites of my enterprise ^^
Another solution appeared to me : to use Microsoft's Azure service. So i created an ASP.net app of which here is the only sample of code. That method sends correctly my email (the first thing I wanted to verify), but it's unable to recover my form's data.
I wanted to use Request.Form.Keys to see what does it recover before I treat my data, and it didn't recover anything so I didn't understand.
I finally created that test String to delete a doubt who was growing. I put a breakpoint on the next line, where my Datetime is instantiate, to see what was in my test ... and it doesn't exist.
Here is the error I can see with my breakpoint :
AzureSendgrid.Controllers.HomeController.SendMail() : test value is error CS0103: The name 'test' doesn't exist in the actual context
public void SendMail()
{
//System.Collections.Specialized.NameObjectCollectionBase.KeysCollection test = Request.Form.Keys;
String test = "test";
System.Diagnostics.Debug.Write(test);
DateTime now = DateTime.Now; // Here is a breakpoint
// Create the email object first, then add the properties.
SendGridMessage myMessage = new SendGridMessage();
myMessage.AddTo(emailTo);
myMessage.From = new MailAddress(emailFrom, "Appli Mobile");
myMessage.Subject = "Appli Mobile Testing SendGrid";
myMessage.Text = "Date-Heure d'envoi : " + now.Day + "/" +
now.Month + " " + now.Hour + ":" + now.Minute + ":" + now.Second;
//myMessage.AddAttachment
// Create a Web transport, using API Key
var transportWeb = new Web(api_key)
// Send the email.
//var t = transportWeb.DeliverAsync(myMessage);
}
That error is pretty clear, and I could have understand it if there was not juste one line between the initialization and use of my test variable.
If anyone can see anything to help me, it would be nice !
Sorry for potential errors in this message, I'm French.

Selenium Webdriver automation with emails

I'm currently trying to use Selenium Webdriver (C#) to automate a Forgot Password -> Reset Password workflow, where the user navigates to a page and supplies their username, and the backend code validates the username, then sends an email with a reset password link to the email address associated with their account.
I'm able to automate the process up to the point where the code sends the email, but I don't know any ways of checking for the email and/or clicking a link in the email, so I was hoping someone more experienced with Selenium/automation may be able to give me a few pointers.
Ideally the test should not care about the email address that the email is being sent to. Is there a way for Selenium WebDriver or some 3rd party package to catch the email being sent?
Thanks for any input or suggestions.
No. You are talking about setting up an email server, which is not an easy task.
You should send it to a test work email (if this is for a company), or a public email (hotmail/gmail), or if security is not an issue at all, the easiest place to send it would be a disposable email (mailinator)
You could try PutsBox. You can send an email to whatever-you-want#putsbox.com, wait for a few seconds (SMTP stuff ins't instantaneous) then check your email via http://preview.putsbox.com/p/whatever-you-want/last.
Have a look at this post tutorial, it can give you some ideas.
There is no integration of selenium with email clients like Thunderbird/Outlook. But if you have a web interface of the same email client, then you can access the email from browser and using selenium you can read and respond to the emails. I have tried this recently and it works fine where I have used web Outlook for testing.
Hope this helps.
Hi I was in a similar situation and was able to successfully implement a way to get an activation or forgotten password links.
Using Java Mail API I was able to trigger a method when such action is performed which goes into a Folder and read a specific message line then get the link and open it up in a browser using WebDriver.
However the main drawback with this is the inconsistency of reading a specific folder, sometimes emails goes to spam or other folder (in case of Gmail the new Social Folder) making it invisible or difficult to be retrieved.
Overall i think its a process that shouldn't really be automated, In terms of testing it should be done more code base level by mocking responses.
Snippet below should give you an idea on how to go about implementing
public class RefactoredMail {
public static void main(String[] args) {
Properties props = new Properties();
props.setProperty("mail.store.protocol", "imaps");
try {
Session session = Session.getInstance(props, null);
Store store = session.getStore();
store.connect("imap.gmail.com", "username", "password");
Folder inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_ONLY);
Message msg = inbox.getMessage(inbox.getMessageCount());
Address[] in = msg.getFrom();
for (Address address : in) {
System.out.println("FROM:" + address.toString());
}
Multipart mp = (Multipart) msg.getContent();
BodyPart bp = mp.getBodyPart(0);
System.out.println("SENT DATE:" + msg.getSentDate());
System.out.println("SUBJECT:" + msg.getSubject());
System.out.println("CONTENT:" + bp.getContent());
System.out.println("Activation Link:" + ((String)
bp.getContent()).startsWith("http"));
String [] line = new String[1];
line [0] = mp.getContentType().toString();
System.out.println("Activation Link:" + (mp.getBodyPart(0).getLineCount()));
System.out.println("Activation Link:" +line[0]);
} catch (Exception e) {
e.printStackTrace();
}
//WebDriver Stuffs
public String activationUrl() {
//getting the url link and making it a global variable .... etc
//Accessing the link
}
}
You can use https://github.com/cmendible/netDumbster or http://ndumbster.sourceforge.net/default.html. I've used one i forget which. This will host an smtp listener and allow you to make assertions against any email it receives. Its kind of awesome! The caveat is you need to be able to control where the server delivers mail in the environment you are testing.

Sending email using Smtp.mail.microsoftonline.com

The context:
We’re a small company that does not have an Exchange Server (or anyone dedicated to it) yet we still need to have/send emails.
We’ve decided to use Microsoft Online Services (MOS)
The Objective:
We have a web server (Windows Server 2003 R2 with IIS 6.0) and have deployed a C# ASP.Net MCV application.
The web application needs to send emails each time a user creates an account.
According to the documentation we need to use port (587) and make sure Transport Layer Security (TLS) enable. In addition, the FROM address being used must be of type “Authoritative” which it is when I double check via the Microsoft Online Administration Center
The code:
The C# code I have should be trivial and is the following:
SmtpClient server = new SmtpClient("Smtp.mail.microsoftonline.com");
server.Port = 587;
server.EnableSsl = true;
server.Credentials = new System.Net.NetworkCredential("xxx#domain.com", "123abc");
server.UseDefaultCredentials = false;
MailMessage mail = new MailMessage();
mail.From = new MailAddress("xxx#domain.com");
mail.To.Add("johndoe#domain.com");
mail.Subject = "test subject";
mail.Body = "this is my message body";
mail.IsBodyHtml = true;
try
{
server.Send(mail);
}
catch (Exception ex)
{
throw ex;
}
The error:
I’ve created a simple winform application with the above code to test the sending of emails…
I’ve tested the winform application locally on my computer (Windows XP) and on the Server.
In both attempt, I keep receiving the following error message:
The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.1 Client was not authenticated.
After Googling for a while I still haven’t found the reason why…In addition, most of the answers I’ve found are making a reference to the Exchange Management Console which we don’t seem to have (or installed) hence why we are using Microsoft Online Services…
Questions:
1) As a paying customer of MOS, my initial understanding is that I shouldn’t have to install (or have) an Exchange Management Console on our server…in fact, this should be completely irrelevant in order to achieve my task.
2) I’ve also tried enabling TLS inside our IIS 6.0 but to no avail…
3) We are grasping at straws here because what we seem to do looks like something amazingly trivial…
4) Should we simply abandon the idea of using MOS’s SMTP server and use another one? Such as Gmail’s ? If so…then why bother paying a monthly fee for MOS?
If any one has any help/advice that can help me shed some light on this, that would be great!
Sincerely
Vince
WOW…I believe we’ve found the culprit!!!
By commenting this line of code:
//server.UseDefaultCredentials = false;
Everything started to work!
I’m now able to send emails inside and outside our domain…
What puzzles me the most is that, according to the documentation, the default value of this UseDefaultCredentials property is set to false
So…when I manually set it to false it doesn’t work but when I comment the line (which also set’s it to false because of its default value) it works!
If this is a known issue or if anyone has an answer for that, I’d be curious to know!
looking in Reflector on UseDefaultCredentials property, you can see that it also changes the trasnport.Credentials value, so when you called this property with a false value, it changed the transport credentials to null.
the problem is that you called this property after setting the credentials in the line before that,
it nullified the credentials.
so bottom line, you shouldn't set the credentials and call this property afterwise.
you can try this sample
private void Button1_Click(System.Object sender, System.EventArgs e)
{
try
{
MailMessage myMessage = new MailMessage();
SmtpClient myClient = new SmtpClient("yourserver");
myClient.Port = "587";
myClient.Host = "your server";
myClient.UseDefaultCredentials = false;
myClient.Credentials = new System.Net.NetworkCredential("username", "password");
myMessage.From = new MailAddress("sender");
myMessage.To.Add("recipient");
myMessage.Subject = "Subject email";
myMessage.Body = "body email";
myClient.EnableSsl = true;
myClient.Send(myMessage);
}
catch (Exepiton ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
Bye
5.7.1 is not an authentication issue, but a relay issue. In order to prevent anyone from using your server (or account, as the case may be) the smtp server is configured to only allow mail to users outside your domain if it is comming from an authoritive address. Verify that the address you have listed here
mail.From = new MailAddress("xxx#domain.com");
is the same as the one you are authenticating as. Also, make sure that the domain of the address listed is in the authoritive domains list.
What worked for me was what the-dude suggested Send SMTP email using System.Net.Mail via Exchange Online (Office 365) , on changing the email "from" address to be the same as the login for the stmp address
AND
doing what Vince suggested at the end Sending email using Smtp.mail.microsoftonline.com for commenting out "smtpClient.UseDefaultCredentials = false;"
Be sure to double check that your username is correct. It is not necessarily the same as your from email address. For example the from address may be "no-reply#yourdomain.com" but the username could be "mail-svc#yourdomain.onmicrosoft.com" depending no your setup and integration with Azure Active Directory etc.

C#: What is the best method to send support request via email?

I have a windows forms application that I am adding a request support form to, and would like the user to be able to input the values and hit a button. Once the button is pushed I can either:
Open a new mail message and auto populate the message. (Not sure how to do this)
Submit the request via a http form on my website. (I know how to do this)
Send an email directly from the code of the application. (I know how to do this)
What I want to know is what would be the best method to use? I think option 1 is the most transparent, and the user will see exactly what is being sent, but I am not sure how to ensure it works no matter what email client they use.
I see there being potential issues with option two, specifically a firewall possibly stopping the submission. But option 2 would allow me to supply them with a ticket number right then and there for their request.
Thanks for the help.
For Option 1, as suggested, use the mailto handler.
Format your string like so: string.Format("mailto:support#example.com?subject={0}&body={1}", subject, body). Don't forget to UrlEncode the subject and body values.
Then use System.Diagnostics.Process.Start() with your string.
This will launch the registered mail handler (Outlook, Windows Live Mail, Thunderbird, etc) on the system.
For option 1 : If the message body is short, then invoking the mailto handler from inside your code no longer requires that they be using outlook. It's kinda a cheap hack, but it's completely cross-platform for local mail clients. (If they're using something like gmail, you're still SOL, though)
Option 2) is the best to avoid enterprise firewall issues because the HTTP port may not be blocked.
Option 2) is the best for simple configuration. The only config key you will have is the service/page url. Then your SMTP configuration will stay on your webserver.
Now you will have to choose between using a webpage (if one already exists) or a webservice (which is best fitted for your feature).
For option (1) be prepared to deal with Outlook version problems. But this is not hard (again if we are talking about Outlook, last version)
//using Microsoft.Office.Interop.Outlook;
private void OutlookMail(string Subject, string Body)
{
ApplicationClass app = new ApplicationClass();
NameSpaceClass ns = (NameSpaceClass)app.GetNamespace("mapi");
ns.Logon("", "", true, true);
MailItem mi =
(MailItem)app.CreateItem(OlItemType.olMailItem);
mi.Subject = Subject;
int EOFPos = Body.IndexOf(char.Parse("\0"));
if (EOFPos != -1)
{
log.Error("EOF found in Mail body");
ErrorDialog ed = new ErrorDialog(TietoEnator.Common.ErrorDialog.ErrorDialog.Style.OK, "Export Error", "File could not be exported correctly, please inform responsible person", "", "EOF char detected in the body of email message.");
ed.ShowDialog();
Body=Body.Replace("\0", "");
}
mi.HTMLBody = "<html><head><META content='text/html; charset=CP1257' http-equiv=Content-Type></head><body><table>"+Body+"</table></body></html>";
mi.BodyFormat = OlBodyFormat.olFormatHTML;//.olFormatPlain;
mi.Display(0); // show it non - modally
ns.Logoff();
}
BTW for automatic support requests I plan to use in my current project "Microsoft Enterprise Logging Support Block" email sending functionality.

Categories