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>
Related
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
i'm trying to log in a site with username + password through a c# code.
i found out that it uses Ajax to authenticate...
how should i implement such login ?
the elements in the web page doesn't seem to have an "id"...
i tried to implement it using HtmlAgilityPack but i don't think this is the correct direction...
i can't simulate a click button since i don't find "id" for the button.
if (tableNode.Attributes["class"].Value == "loginTable")
{
var userInputNode =
tableNode.SelectSingleNode("//input[#data-logon-popup-form-user-name-input='true']");
var passwordInputNode =
tableNode.SelectSingleNode("//input[#data-logon-popup-form-password-input='true']");
userInputNode.SetAttributeValue("value", "myemail#gmail.com");
passwordInputNode.SetAttributeValue("value", "mypassword");
var loginButton = tableNode.SelectSingleNode("//div[#data-logon-popup-form-submit-btn='true']");
}
This question is quite broad but I'll help you in the general direction:
Use Chrome DevTools (F12) => Network tab => Check the "Preserve Log". An alternative could be Fiddler2
Login manually and look at the request the AJAX sends. Save the endpoint (the URL) and save the Body of the request (the Json data that's in the request with username and password)
Do the post directly in your C# code and forget about HtmlAgilityPack unless you need to actually get some dynamic data from the page, but that's rarely the case
Login with something like this code snippet: POSTing JSON to URL via WebClient in C#
Now you're logged in. You usually receive some data from the server when you're logging in, so save it and use it for whatever you want to do next. I'm guessing it might have some SessionId or some authentication token that your future requests will need as a parameter to prove that you're actually logged in.
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.
I'm trying to create a .NET-based client app (in WPF - although for the time being I'm just doing it as a console app) to integrate with an OAuth-enabled application, specifically Mendeley (http://dev.mendeley.com), which apparently uses 3-legged OAuth.
This is my first time using OAuth, and I'm having a lot of difficulty getting started with it. I've found several .NET OAuth libraries or helpers, but they seem to be more complicated than I think I need. All I want to do is be able to issue REST requests to the Mendeley API and get responses back!
So far, I've tried:
DotNetOpenAuth
http://github.com/bittercoder/DevDefined.OAuth
http://oauth.googlecode.com/svn/code/csharp/
The first (DotNetOpenAuth) seems like it could possibly do what I needed if I spent hours and hours trying to work out how. The second and third, as best I can tell, don't support the verification codes that Mendeley is sending back -- although I could be wrong about this :)
I've got a consumer key and secret from Mendeley, and with DotNetOpenAuth I managed to get a browser launched with the Mendeley page providing a verification code for the user to enter into the application. However, at this point I got lost and couldn't work out how to sensibly provide that back to the application.
I'm very willing to admit that I have no idea where to start with this (although it seems like there's quite a steep learning curve) - if anyone can point me in the right direction I'd appreciate it!
I agree with you. The open-source OAuth support classes available for .NET apps are hard to understand, overly complicated (how many methods are exposed by DotNetOpenAuth?), poorly designed (look at the methods with 10 string parameters in the OAuthBase.cs module from that google link you provided - there's no state management at all), or otherwise unsatisfactory.
It doesn't need to be this complicated.
I'm not an expert on OAuth, but I have produced an OAuth client-side manager class, that I use successfully with Twitter and TwitPic. It's relatively simple to use. It's open source and available here: Oauth.cs
For review, in OAuth 1.0a...kinda funny, there's a special name and it looks like a "standard" but as far as I know the only service that implements "OAuth 1.0a" is Twitter. I guess that's standard enough. ok, anyway in OAuth 1.0a, the way it works for desktop apps is this:
You, the developer of the app, register the app and get a "consumer key" and "consumer secret". On Arstechnica, there's a well written analysis of why this model isn't the best, but as they say, it is what it is.
Your app runs. The first time it runs, it needs to get the user to explicitly grant approval for the app to make oauth-authenticated REST requests to Twitter and its sister services (like TwitPic). To do this you must go through an approval process, involving explicit approval by the user. This happens only the first time the app runs. Like this:
request a "request token". Aka temporary token.
pop a web page, passing that request token as a query param. This web page presents UI to the user, asking "do you want to grant access to this app?"
the user logs in to the twitter web page, and grants or denies access.
the response html page appears. If the user has granted access, there's a PIN displayed in a 48-pt font
the user now needs to cut/paste that pin into a windows form box, and click "Next" or something similar.
the desktop app then does an oauth-authenticated request for an "Access token". Another REST request.
the desktop app receives the "access token" and "access secret".
After the approval dance, the desktop app can just use the user-specific "access token" and "access secret" (along with the app-specific "consumer key" and "consumer secret") to do authenticated requests on behalf of the user to Twitter. These don't expire, although if the user de-authorizes the app, or if Twitter for some reason de-authorizes your app, or if you lose your access token and/or secret, you'd need to do the approval dance again.
If you're not clever, the UI flow can sort of mirror the multi-step OAuth message flow. There is a better way.
Use a WebBrowser control, and open the authorize web page within the desktop app. When the user clicks "Allow", grab the response text from that WebBrowser control, extract the PIN automatically, then get the access tokens. You send 5 or 6 HTTP requests but the user needs to see only a single Allow/Deny dialog. Simple.
Like this:
If you've got the UI sorted, the only challenge that remains is to produce oauth-signed requests. This trips up lots of people because the oauth signing requirements are sort of particular. That's what the simplified OAuth Manager class does.
Example code to request a token:
var oauth = new OAuth.Manager();
// the URL to obtain a temporary "request token"
var rtUrl = "https://api.twitter.com/oauth/request_token";
oauth["consumer_key"] = MY_APP_SPECIFIC_KEY;
oauth["consumer_secret"] = MY_APP_SPECIFIC_SECRET;
oauth.AcquireRequestToken(rtUrl, "POST");
THAT'S IT. Simple. As you can see from the code, the way to get to oauth parameters is via a string-based indexer, something like a dictionary. The AcquireRequestToken method sends an oauth-signed request to the URL of the service that grants request tokens, aka temporary tokens. For Twitter, this URL is "https://api.twitter.com/oauth/request_token". The oauth spec says you need to pack up the set of oauth parameters (token, token_secret, nonce, timestamp, consumer_key, version, and callback), in a certain way (url-encoded and joined by ampersands), and in a lexicographically-sorted order, generate a signature on that result, then pack up those same parameters along with the signature, stored in the new oauth_signature parameter, in a different way (joined by commas). The OAuth manager class does this for you automatically. It generates nonces and timestamps and versions and signatures automatically - your app doesn't need to care or be aware of that stuff. Just set the oauth parameter values and make a simple method call. the manager class sends out the request and parses the response for you.
Ok, then what? Once you get the request token, you pop the web browser UI in which the user will explicitly grant approval. If you do it right, you'll pop this in an embedded browser. For Twitter, the URL for this is "https://api.twitter.com/oauth/authorize?oauth_token=" with the oauth_token appended. Do this in code like so:
var url = SERVICE_SPECIFIC_AUTHORIZE_URL_STUB + oauth["token"];
webBrowser1.Url = new Uri(url);
(If you were doing this in an external browser you'd use System.Diagnostics.Process.Start(url).)
Setting the Url property causes the WebBrowser control to navigate to that page automatically.
When the user clicks the "Allow" button a new page will be loaded. It's an HTML form and it works the same as in a full browser. In your code, register a handler for the DocumentedCompleted event of the WebBrowser control, and in that handler, grab the pin:
var divMarker = "<div id=\"oauth_pin\">"; // the div for twitter's oauth pin
var index = webBrowser1.DocumentText.LastIndexOf(divMarker) + divMarker.Length;
var snip = web1.DocumentText.Substring(index);
var pin = RE.Regex.Replace(snip,"(?s)[^0-9]*([0-9]+).*", "$1").Trim();
That's a bit of HTML screen scraping.
After grabbing the pin, you don't need the web browser any more, so:
webBrowser1.Visible = false; // all done with the web UI
...and you might want to call Dispose() on it as well.
The next step is getting the access token, by sending another HTTP message along with that pin. This is another signed oauth call, constructed with the oauth ordering and formatting I described above. But once again this is really simple with the OAuth.Manager class:
oauth.AcquireAccessToken(URL_ACCESS_TOKEN,
"POST",
pin);
For Twitter, that URL is "https://api.twitter.com/oauth/access_token".
Now you have access tokens, and you can use them in signed HTTP requests. Like this:
var authzHeader = oauth.GenerateAuthzHeader(url, "POST");
...where url is the resource endpoint. To update the user's status, it would be "http://api.twitter.com/1/statuses/update.xml?status=Hello".
Then set that string into the HTTP Header named Authorization.
To interact with third-party services, like TwitPic, you need to construct a slightly different OAuth header, like this:
var authzHeader = oauth.GenerateCredsHeader(URL_VERIFY_CREDS,
"GET",
AUTHENTICATION_REALM);
For Twitter, the values for the verify creds url and realm are "https://api.twitter.com/1/account/verify_credentials.json", and "http://api.twitter.com/" respectively.
...and put that authorization string in an HTTP header called X-Verify-Credentials-Authorization. Then send that to your service, like TwitPic, along with whatever request you're sending.
That's it.
All together, the code to update twitter status might be something like this:
// the URL to obtain a temporary "request token"
var rtUrl = "https://api.twitter.com/oauth/request_token";
var oauth = new OAuth.Manager();
// The consumer_{key,secret} are obtained via registration
oauth["consumer_key"] = "~~~CONSUMER_KEY~~~~";
oauth["consumer_secret"] = "~~~CONSUMER_SECRET~~~";
oauth.AcquireRequestToken(rtUrl, "POST");
var authzUrl = "https://api.twitter.com/oauth/authorize?oauth_token=" + oauth["token"];
// here, should use a WebBrowser control.
System.Diagnostics.Process.Start(authzUrl); // example only!
// instruct the user to type in the PIN from that browser window
var pin = "...";
var atUrl = "https://api.twitter.com/oauth/access_token";
oauth.AcquireAccessToken(atUrl, "POST", pin);
// now, update twitter status using that access token
var appUrl = "http://api.twitter.com/1/statuses/update.xml?status=Hello";
var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST");
var request = (HttpWebRequest)WebRequest.Create(appUrl);
request.Method = "POST";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.Headers.Add("Authorization", authzHeader);
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode != HttpStatusCode.OK)
MessageBox.Show("There's been a problem trying to tweet:" +
Environment.NewLine +
response.StatusDescription);
}
OAuth 1.0a is sort of complicated under the covers, but using it doesn't need to be.
The OAuth.Manager handles the generation of outgoing oauth requests, and the receiving and processing of oauth content in the responses. When the Request_token request gives you an oauth_token, your app doesn't need to store it. The Oauth.Manager is smart enough to do that automatically. Likewise when the access_token request gets back an access token and secret, you don't need to explicitly store those. The OAuth.Manager handles that state for you.
In subsequent runs, when you already have the access token and secret, you can instantiate the OAuth.Manager like this:
var oauth = new OAuth.Manager();
oauth["consumer_key"] = CONSUMER_KEY;
oauth["consumer_secret"] = CONSUMER_SECRET;
oauth["token"] = your_stored_access_token;
oauth["token_secret"] = your_stored_access_secret;
...and then generate authorization headers as above.
// now, update twitter status using that access token
var appUrl = "http://api.twitter.com/1/statuses/update.xml?status=Hello";
var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST");
var request = (HttpWebRequest)WebRequest.Create(appUrl);
request.Method = "POST";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.Headers.Add("Authorization", authzHeader);
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode != HttpStatusCode.OK)
MessageBox.Show("There's been a problem trying to tweet:" +
Environment.NewLine +
response.StatusDescription);
}
You can download a DLL containing the OAuth.Manager class here. There is also a helpfile in that download. Or you can view the helpfile online.
See an example of a Windows Form that uses this manager here.
WORKING EXAMPLE
Download a working example of a command-line tool that uses the class and technique described here:
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.