Unable to create a new mail with multiple recipients with mailto uri - c#

I am using creating a Windows 8.1 Store App in WinRT.
I am unable to create a new mail with multiple recipients with the mailto uri by separating each email with either comma or semi colon, both gives me the same error.
Invalid URI: The hostname could not be parsed.
the mailto strings looks like this
"mailto:username#mail.com,username2#mail.com"
"mailto:username#mail.com,username2#mail.com,"
"mailto:username#mail.com, username2#mail.com"
"mailto:username#mail.com;username2#mail.com"
"mailto:username#mail.com;username2#mail.com;"
"mailto:username#mail.com; username2#mail.com"
I have tried all these variants an all give me the same error when newing up the uri, like this.
var uri = new Uri(string.Format("mailto:{0}", mails));
I have no idea what I am doing wrong, or in case its not implemented why it wouldn't be?
I created a few unit tests to see if any variations would work, but no..
[TestClass]
public class UriMailToTest
{
private Uri CreateMailToUri(string mail)
{
if (string.IsNullOrEmpty(mail)) throw new ArgumentNullException("mail");
var uriMailTo = string.Format("mailto:{0}", mail);
return new Uri(uriMailTo);
}
[TestMethod]
public void CreateMailToUriTest1()
{
const string mailto = "username#mail.com";
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest2()
{
const string mailto = "username#mail.com,username2#mail.com";
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest3()
{
const string mailto = "username#mail.com,username2#mail.com,";
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest4()
{
const string mailto = "username#mail.com;username2#mail.com";
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest5()
{
const string mailto = "username#mail.com;username2#mail.com;";
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest6()
{
const string mailto = "username#mail.com, username2#mail.com";
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest7()
{
const string mailto = "username#mail.com; username2#mail.com";
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest8()
{
var mails = new[] { "username#mail.com", "username2#mail.com"};
var mailto = mails.Select(WebUtility.UrlEncode).Aggregate((c, n) => string.Format("{0},{1}", c, n));
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest9()
{
var mails = new[] { "username#mail.com", "username2#mail.com" };
var mailto = mails.Select(WebUtility.UrlEncode).Aggregate((c, n) => string.Format("{0};{1}", c, n));
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest10()
{
var mails = new[] { "username#mail.com", "username2#mail.com" };
var mailto = mails.Aggregate((c, n) => string.Format("{0},{1}", c, n));
var urlEncodedMailTo = WebUtility.UrlEncode(mailto);
var uri = CreateMailToUri(urlEncodedMailTo);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest11()
{
var mails = new[] { "username#mail.com", "username2#mail.com" };
var mailto = mails.Aggregate((c, n) => string.Format("{0};{1}", c, n));
var urlEncodedMailTo = WebUtility.UrlEncode(mailto);
var uri = CreateMailToUri(urlEncodedMailTo);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest12()
{
var mails = new[] { "username#mail.com", "username2#mail.com" };
var mailto = mails.Select(WebUtility.UrlEncode).Aggregate((c, n) => string.Format("{0}, {1}", c, n));
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest13()
{
var mails = new[] { "username#mail.com", "username2#mail.com" };
var mailto = mails.Select(WebUtility.UrlEncode).Aggregate((c, n) => string.Format("{0}; {1}", c, n));
var uri = CreateMailToUri(mailto);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest14()
{
var mails = new[] { "username#mail.com", "username2#mail.com" };
var mailto = mails.Aggregate((c, n) => string.Format("{0}, {1}", c, n));
var urlEncodedMailTo = WebUtility.UrlEncode(mailto);
var uri = CreateMailToUri(urlEncodedMailTo);
uri.Should().NotBeNull();
}
[TestMethod]
public void CreateMailToUriTest15()
{
var mails = new[] { "username#mail.com", "username2#mail.com" };
var mailto = mails.Aggregate((c, n) => string.Format("{0}; {1}", c, n));
var urlEncodedMailTo = WebUtility.UrlEncode(mailto);
var uri = CreateMailToUri(urlEncodedMailTo);
uri.Should().NotBeNull();
}
}
with Windows Key + R (Run) typing in mailto:username#mail.com;username2#mail.com works great, I'm just not able to create an Uri object with multiple recipients...
According to the mailto:Protocol # msdn i should be able to use the mailto protocol with multiple recipients.
Syntax
mailto:sAddress[sHeaders]
Tokens
sAddress
One or more valid e-mail addresses separated by a semicolon. You must use Internet-safe characters, such as %20 for the space character.
sHeaders
Optional. One or more name-value pairs. The first pair should be prefixed by a "?" and any additional pairs should be prefixed by a "&". The name can be one of the following strings.
subject
Text to appear in the subject line of the message.
body
Text to appear in the body of the message.
CC
Addresses to be included in the "cc" (carbon copy) section of the message.
BCC
Addresses to be included in the "bcc" (blind carbon copy) section of the message.

There is a hack, using the HyperLinkButton (sorry, this is a dirty hack) :
Load an hyperlinkbutton using a XAmlReader,
Retrieve its AutomationPeer,
Launch a click
var uriString = "mailto:username#mail.com,username2#mail.com";
string xamlString = "<HyperlinkButton "
+ "xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" "
+ "NavigateUri=\"" + uriString + "\"/>";
var c = (HyperlinkButton)XamlReader.Load(xamlString);
new HyperlinkButtonAutomationPeer(c).Invoke();

Try adding 2 forward slashes after the hostname like this : mailto://

cant you follow this code?
System.Net.Mail.MailMessage email = new System.Net.Mail.MailMessage();
email.To.Add("abcd#mail.com");
email.CC.add("abcd1#mail.com");
email.CC.add("abcd2#mail.com");
email.CC.add("abcd2#mail.com");

Related

SEndGrid not replacing Dynamics Data

My one template is not replacing dynamics data in the email
My Code is given below
public static System.Net.HttpStatusCode SendEmailV2(DynamicsModel dynamicsmodel, string templateId, TraceWriter log)
{
log.Info("Executing SendEmailV2");
var SendGridApiCode = System.Environment.GetEnvironmentVariable("SendGridApiCode", EnvironmentVariableTarget.Process);
var fromEmail = System.Environment.GetEnvironmentVariable("FromEmail", EnvironmentVariableTarget.Process);
var fromName = System.Environment.GetEnvironmentVariable("FromName", EnvironmentVariableTarget.Process);
var dynamicTemplateData = new DynamicData
{
Name = dynamicsmodel.FullName
};
string output = JsonConvert.SerializeObject(dynamicTemplateData);
log.Info("json:" + output);
EmailAddress from = new EmailAddress(fromEmail, "test name");
EmailAddress to = new EmailAddress(dynamicsmodel.Email, dynamicsmodel.FullName);
var sendGridClient = new SendGridClient(SendGridApiCode);
var sendGridMessage = CreateSingleTemplateEmail(from, to, templateId, dynamicTemplateData);
var response = sendGridClient.SendEmailAsync(sendGridMessage).Result;
if (response.StatusCode == System.Net.HttpStatusCode.Accepted)
{
log.Info("Emails Sent from SendGrid");
}
else
{
log.Info("response.StatusCode:" + response.StatusCode.ToString());
}
return response.StatusCode;
}
My JSON which is being passed is given below
{"name":"Test User"}
This happens to one template only. Any help will be much appreciated

HttpUtility.ParseQueryString missing some characters

I'm trying to extract en email with the + special character but for some reason the ParseQueryString skips it:
namespace ParsingProblem
{
class Program
{
static void Main(string[] args)
{
var uri = new System.Uri("callback://gmailauth/#email=mypersonalemail15+1#gmail.com");
var parsed = System.Web.HttpUtility.ParseQueryString(uri.Fragment);
var email = parsed["#email"];
// Email is: mypersonalemail15 1#gmail.com and it should be mypersonalemail15+1#gmail.com
}
}
}
The + symbol in a URL is interpreted as a space character. To fix that, you need to URL encode the email address first. For example:
var urlEncodedEmail = System.Web.HttpUtility.UrlEncode("mypersonalemail15+1#gmail.com");
var uri = new System.Uri($"callback://gmailauth/#email={urlEncodedEmail}");
var parsed = System.Web.HttpUtility.ParseQueryString(uri.Fragment);
var email = parsed["#email"];

Get Content-Disposition parameters

How do I get Content-Disposition parameters I returned from WebAPI controller using WebClient?
WebApi Controller
[Route("api/mycontroller/GetFile/{fileId}")]
public HttpResponseMessage GetFile(int fileId)
{
try
{
var file = GetSomeFile(fileId)
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(new MemoryStream(file));
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = file.FileOriginalName;
/********* Parameter *************/
response.Content.Headers.ContentDisposition.Parameters.Add(new NameValueHeaderValue("MyParameter", "MyValue"));
return response;
}
catch(Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
}
}
Client
void DownloadFile()
{
WebClient wc = new WebClient();
wc.DownloadDataCompleted += wc_DownloadDataCompleted;
wc.DownloadDataAsync(new Uri("api/mycontroller/GetFile/18"));
}
void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
WebClient wc=sender as WebClient;
// Try to extract the filename from the Content-Disposition header
if (!String.IsNullOrEmpty(wc.ResponseHeaders["Content-Disposition"]))
{
string fileName = wc.ResponseHeaders["Content-Disposition"].Substring(wc.ResponseHeaders["Content-Disposition"].IndexOf("filename=") + 10).Replace("\"", ""); //FileName ok
/****** How do I get "MyParameter"? **********/
}
var data = e.Result; //File OK
}
I'm returning a file from WebApi controller, I'm attaching the file name in the response content headers, but also I'd like to return an aditional value.
In the client I'm able to get the filename, but how do I get the aditional parameter?
If you are working with .NET 4.5 or later, consider using the System.Net.Mime.ContentDisposition class:
string cpString = wc.ResponseHeaders["Content-Disposition"];
ContentDisposition contentDisposition = new ContentDisposition(cpString);
string filename = contentDisposition.FileName;
StringDictionary parameters = contentDisposition.Parameters;
// You have got parameters now
Edit:
otherwise, you need to parse Content-Disposition header according to it's specification.
Here is a simple class that performs the parsing, close to the specification:
class ContentDisposition {
private static readonly Regex regex = new Regex(
"^([^;]+);(?:\\s*([^=]+)=((?<q>\"?)[^\"]*\\k<q>);?)*$",
RegexOptions.Compiled
);
private readonly string fileName;
private readonly StringDictionary parameters;
private readonly string type;
public ContentDisposition(string s) {
if (string.IsNullOrEmpty(s)) {
throw new ArgumentNullException("s");
}
Match match = regex.Match(s);
if (!match.Success) {
throw new FormatException("input is not a valid content-disposition string.");
}
var typeGroup = match.Groups[1];
var nameGroup = match.Groups[2];
var valueGroup = match.Groups[3];
int groupCount = match.Groups.Count;
int paramCount = nameGroup.Captures.Count;
this.type = typeGroup.Value;
this.parameters = new StringDictionary();
for (int i = 0; i < paramCount; i++ ) {
string name = nameGroup.Captures[i].Value;
string value = valueGroup.Captures[i].Value;
if (name.Equals("filename", StringComparison.InvariantCultureIgnoreCase)) {
this.fileName = value;
}
else {
this.parameters.Add(name, value);
}
}
}
public string FileName {
get {
return this.fileName;
}
}
public StringDictionary Parameters {
get {
return this.parameters;
}
}
public string Type {
get {
return this.type;
}
}
}
Then you can use it in this way:
static void Main() {
string text = "attachment; filename=\"fname.ext\"; param1=\"A\"; param2=\"A\";";
var cp = new ContentDisposition(text);
Console.WriteLine("FileName:" + cp.FileName);
foreach (DictionaryEntry param in cp.Parameters) {
Console.WriteLine("{0} = {1}", param.Key, param.Value);
}
}
// Output:
// FileName:"fname.ext"
// param1 = "A"
// param2 = "A"
The only thing that should be considered when using this class is it does not handle parameters (or filename) without a double quotation.
Edit 2:
It can now handle file names without quotations.
You can parse out the content disposition using the following framework code:
var content = "attachment; filename=myfile.csv";
var disposition = ContentDispositionHeaderValue.Parse(content);
Then just take the pieces off of the disposition instance.
disposition.FileName
disposition.DispositionType
With .NET Core 3.1 and more the most simple solution is:
using var response = await Client.SendAsync(request);
response.Content.Headers.ContentDisposition.FileName
The value is there I just needed to extract it:
The Content-Disposition header is returned like this:
Content-Disposition = attachment; filename="C:\team.jpg"; MyParameter=MyValue
So I just used some string manipulation to get the values:
void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
WebClient wc=sender as WebClient;
// Try to extract the filename from the Content-Disposition header
if (!String.IsNullOrEmpty(wc.ResponseHeaders["Content-Disposition"]))
{
string[] values = wc.ResponseHeaders["Content-Disposition"].Split(';');
string fileName = values.Single(v => v.Contains("filename"))
.Replace("filename=","")
.Replace("\"","");
/********** HERE IS THE PARAMETER ********/
string myParameter = values.Single(v => v.Contains("MyParameter"))
.Replace("MyParameter=", "")
.Replace("\"", "");
}
var data = e.Result; //File ok
}
As #Mehrzad Chehraz said you can use the new ContentDisposition class.
using System.Net.Mime;
// file1 is a HttpResponseMessage
FileName = new ContentDisposition(file1.Content.Headers.ContentDisposition.ToString()).FileName

Parse variable URI (RegEx, Uri, String-Functions?) c#

I'm writing a RTSP client module and for this, I need to parse an very variable URI. But I'm completely stuck about which method I should use (most-failsafe) and how to accomplish this.
An example URI could look like this:
rtsp://192.168.1.100:554/videocam/media/1/video/1
\_/ \_______________/\_______/\______________/
| | | |
scheme authority [sub] [mediacontrol]
But also other possibilities:
192.168.1.100/videocam/media/1/video/1
192.168.1.100:6000/media/1/video/1
192.168.1.100:6000/videocam
I need the following information:
IP | how can I recognise this pattern [num].[num].[num].[num]?
Port | easy if the string contains rtsp://, but what about just a number? 1-65555
Sub | Optional subpath, can completely vary!
MediaLevel | Optional MediaLevel (indicator for stream/track),
not to be confused with the path. MediaLevel can be also just like this: track1 or m1s3 or media1/video1.. see?
I can't go for the slash, also the path also can contain multiple slashes
Maybe there's a library for such tasks?
Thank you.
var uri = new Uri("rtsp://192.168.1.100:554/videocam/media/1/video/1");
var host = uri.Host;
var port = uri.Port;
var sub = uri.Segments[1];
var mlevel = uri.Segments.Skip(2).ToArray();
Here is a quick example of how to use the UriBuilder class. It is a bit verbose because it is an example and is not ready for production. If more subs are to be identified then they can be added to the Sub List as shown in the example.
class Program
{
private static string _scheme = string.Empty;
private static string _host = string.Empty;
private static string _sub = string.Empty;
static void Main(string[] args)
{
ParseUri("rtsp://192.168.1.100:554/videocam/media/1/video/1");
ParseUri("192.168.1.100/videocam/media/1/video/1");
ParseUri("192.168.1.100:6000/media/1/video/1");
ParseUri("192.168.1.100:6000/videocam");
// example of adding a new sub
Sub.Add("sample");
ParseUri("192.168.1.100:6000/sample/");
Console.ReadLine();
}
private static void ParseUri(string URI)
{
UriBuilder uri = new UriBuilder(URI);
_scheme = uri.Scheme;
_host = uri.Host;
_sub = string.Empty;
StringBuilder sb = new StringBuilder();
foreach (string s in uri.Uri.Segments)
{
if (Sub.Contains(s.Replace("/","")))
{_sub = s;}
else
{ sb.Append(s); }
}
Console.Out.WriteLine("+++++++++++++");
Console.Out.WriteLine("URI: {0}",URI);
Console.Out.WriteLine("Scheme: {0}", _scheme);
Console.Out.WriteLine("sub: {0}",_sub);
Console.Out.WriteLine("mediaControl: {0}", sb.ToString());
}
private static List<string> Sub
{
get
{
List<string> sub = new List<string>();
sub.Add("videocam");
return sub;
}
}
}
trace("Url : {0}", turl.Text);
var uri = new Uri(turl.Text);
string host = uri.Host;
int port = uri.Port;
string userInfo = uri.UserInfo;
string subStream = "";
string userName = "";
string password = "";
if (uri.Segments?.Any() == true)
{
subStream = string.Join("", uri.Segments);
}
if (!string.IsNullOrEmpty(userInfo))
{
if (userInfo.Contains(":"))
{
string[] data = userInfo.Split(':');
userName = data[0];
password = data[1];
}
else
{
userName = userInfo;
}
}
trace("host : {0}", host);
trace("port : {0}", port);
trace("userName : {0}", userName);
trace("password : {0}", password);
trace("subStream: {0}", subStream);

Validate Google Account using WebClient

I am trying validate Google Account using WebClient.
class PostDataBuilder
{
private static Dictionary<string, string>
ToPropertyDictionary(object data)
{
var values = data
.GetType()
.GetProperties()
.Select(x => new {
Key = x.Name,
Value = x.GetValue(data, null)
});
var result = new Dictionary<string, string>();
foreach (var item in values)
result.Add(item.Key, item.Value.ToString());
return result;
}
public static string Build(object data)
{
string result = "";
var dict = ToPropertyDictionary(data);
foreach (var name in dict.Keys)
result += name + "=" + HttpUtility.UrlEncode(dict[name]) + "&";
return result.Substring(0, result.Length - 1);
}
}
class Program
{
static void Main(string[] args)
{
string postText = PostDataBuilder.Build(
new
{
dsh = "-1903339439726094408",
GALX = "-Ggrv6gqusk",
timeStmp = "",
secTok = "",
Email = "WrongEmail#gmail.com",
Passwd = "WrongPassword",
signIn = "?????",
rmShown = "1"
});
byte[] data = Encoding.UTF8.GetBytes(postText);
WebClient wc = new WebClient();
byte[] result = wc.UploadData(
new Uri("https://accounts.google.com/ServiceLoginAuth"),
"POST", data);
string resultText = Encoding.UTF8.GetString(result);
}
}
ResultText variable has setted , even if data is correct. What's wrong?
You shouldn't ever screw around with login services such as the Google one or try to fake a browser. In the end it could be considered attempt hacking or whatever and it's very likely to break the next time they update their page (or even just because your IP changes).
Instead use OpenID or OAuth as described here.

Categories