I have a scenario, to convert the valid email address to test account by adding "test-" in the email address domain. So that on the testing environment it won't reach to the actual recipients. Also I adding my email address in the Bcc to verify that email content.
What I have tried so far:
{
MailMessage msg = new MailMessage();
// already valided the "emailAddress" is the valid one or not
msg.To.Add(new MailAddress(ToTestAccount(emailAddress)));
// other code ...
}
Calling the method ToTestAccount() to add the "test-" in the email address.
private string ToTestAccount(string emailAddress)
{
var userAlias = emailAddress.Split('#')[0];
var host = emailAddress.Split('#')[1].Split('.')[0];
var hostDomain = emailAddress.Split('#')[1];
var indexOfDot = hostDomain.IndexOf('.');
var domain = hostDomain.Substring(indexOfDot, hostDomain.Length - indexOfDot);
return userAlias + "#test-" + host + domain;
}
The functionality produce my expected result. Sample data and expected output:
Email Address | Expected
----------------------------------------------------------
arulkumar#gmail.com | arulkumar#test-gmail.com
arul.kumar#gmail.com | arul.kumar#test-gmail.com
arulkumar4#gmail.co.in | arulkumar4#test-gmail.co.in
arul.kumar4#gmail.co.in | arul.kumar4#test-gmail.co.in
But is there any other way to achieve the expected result, I mean using less string funtions or the best practice to achieve it?
C# Fiddle for the same: https://rextester.com/LPZI50439
For some reason, I'm not able to use SpecifiedPickupDirectory option, so I'm triggering the actual email.
You can use the MailAddress properties which would result in less string manipulation and handle some of the weird varieties of valid email addresses.
private string ToTestAccount(string emailAddress)
{
var originalEmailAddress = new MailAddress(emailAddress);
return $"{originalEmailAddress.User}#test-{originalEmailAddress.Host}";
}
Or if you need to support display names you could have an extension method:
public static MailAddress Testing(this MailAddress address)
{
return string.IsNullOrEmpty(address.DisplayName)
? new MailAddress($"{address.User}#test-{address.Host}")
: new MailAddress($"{address.User}#test-{address.Host}", address.DisplayName);
}
Which would allow usage like this:
{
MailMessage msg = new MailMessage();
// already valided the "emailAddress" is the valid one or not
msg.To.Add(new MailAddress(emailAddress).Testing()));
msg.To.Add(new MailAddress(aDifferentEmailAddress, displayName).Testing()));
// other code ...
}
You can use replace in your case.
private string ToTestAccount(string emailAddress)
{
return emailAddress == null ? emailAddress : emailAddress.Replace("#","#test-");
}
Please note that this solution is valid only in case if you need not to deliver the message to the real user. If you need to change domain to deliver it it may not work as email may contain more than one # symbol. As #andyb952 mentioned in a comment it's very rare but possible.
Related
I am having some issues with my send mail. I made some changes to this and now am getting this error.
When I ran the code before this error, I had this set up to email the first email in the address Detail. The first email in the address detail is Billing. Which would be okay if the email is meant to go to billing. In my system I have a billing address, and a shipping address and sometimes those are the same location. So I added some code and CC so that it sends to the proper email.
Here is my code:
string subject = " Request For Payment";
string body = "Please see the attached Request";
string touser = data.AddressDetail.FirstOrDefault()?.EmailAddress ?? "MyEmailAddress";
string ccAddress = data.AddressDetail.Where(x => x.IsShipping == true).FirstOrDefault()?.EmailAddress;
bool val = ExtendedViewModels.SendEmail(touser, ccAddress, subject, body, FilePath, "InfoEmailAddress");
So the touser will be the first email, the CC will be to the Shipping email. I realize I may send 2 emails if shipping and billing are the same. Not sure how to get around that. This is the first attempt I have made with this code. I should also say that the email is a Canadian email with a .ca although I dont know that this is the issue. This instance is also a case where billing and shipping are the same. This is only 1 record with bits set for billing and shipping.. In other cases there would be 2 records with billing and one with shipping.
Any help would be appreciated - thanks in advance!
UPDATE:
I ran this with breakpoints on the code. I have all the info I am supposed to. It faults when It goes to send the mail. The only thing that sticks out to me is that it is a .ca email and not a .com. Is there something in sendmail that needs to be added for this?
UPDATE:
I found my issue. Order of importance! I guess Order matters. I will put it in an answer below!
Order is Important in this case. While adding the ccAddress I did not take care in where I placed it. I was sending an email to what the subject was..
string subject = " Request For Payment";
string body = "Please see the attached Request";
string touser = data.AddressDetail.FirstOrDefault()?.EmailAddress;
string ccAddress = data.AddressDetail.Where(x => x.IsShipping == true).FirstOrDefault()?.EmailAddress;
if (touser == ccAddress)
{
bool val = ExtendedViewModels.SendEmail(touser, subject, null, body, FilePath, "InfoEmail");
}
else
{
bool val = ExtendedViewModels.SendEmail(touser, subject, ccAddress, body, FilePath, "InfoEmail");
}
Then in the Send mail I had to add an if statement where ccAddress may be null.
public static Boolean SendEmail(string touser, string subject, string ccAddress, string body, string FilePath, string fromAddress)
{
try
{
MailMessage msg = new MailMessage
{
From = new MailAddress(fromAddress)
};
msg.To.Add(touser);
if (ccAddress != null)
{
msg.CC.Add(ccAddress);
}
msg.Subject = subject;
msg.Body = body;
msg.IsBodyHtml = true;
if (FilePath != "")
{
msg.Attachments.Add(new Attachment(FilePath));
}
SmtpClient smt = new SmtpClient
{
Host = "smtp.office365.com",
UseDefaultCredentials = false,
Credentials = new NetworkCredential("Your UserName", "Your Password"),
Port = 587,
DeliveryMethod = SmtpDeliveryMethod.Network,
EnableSsl = true
};
smt.Send(msg);
}
catch (Exception ex)
{
throw ex;
}
return true;
}
}
I put the rest of the code up there to make it a complete answer..
I'm using MailKit to send emails for account confirmation and password reset. These operations work as intended, but now I'm trying to modify the same code to also send email notifications to all registered users but this is where I'm having issues.
I've built a List collection using the following code:
public List<string> UserList {
get {
var allUsers = userManager.Users;
return allUsers.Select(x => x.Email).ToList();
}
}
this collection returns all emails within my AspNetUsers table successfully.
Next I create 3 variables:
var toAddress = UserList;
var subject = "New Asset Added" + " " + model.Name;
var body = model.Name + model.AssetType + model.AssetURL;
When debugging and stepping through the code I do see Count = 2 and then the list of emails in the variable. So far this looks good
After the 3 variables I have this line of code that passes the collected information to the Send method:
_emailSender.Send(toAddress[0], subject, body);
Again, the toAddress[0] when stepping through code shows Count = 2 so I'm assuming the way I have it written is valid.
Once I reach the Send Method code and I check the toAddress variable again, it is now stripped of the Count = 2 and becomes just the first email address in the list which makes sense since I passed the variable with an index of 0. What I really need is to pass all emails not just 1.
If I remove the brackets or leave the brackets empty I get an error:
cannot convert from 'System.Collections.Generic.List<string>' to 'string'
So for now I'm forced to add an index.
My send method seems fairly simple but I do believe my foreach loop might also not be well formulated. Here's my Send Method in it's entirety.
public async void Send(string toAddress, string subject, string body, bool sendAsync = true) {
var mimeMessage = new MimeMessage(); // MIME : Multipurpose Internet Mail Extension
mimeMessage.From.Add(new MailboxAddress(_fromAddressTitle, _fromAddress));
foreach (char toAddresses in toAddress) {
mimeMessage.To.Add(new MailboxAddress(toAddresses)); //I get error saying cannot convert char to string.
}
mimeMessage.Subject = subject;
var bodyBuilder = new MimeKit.BodyBuilder {
HtmlBody = body
};
mimeMessage.Body = bodyBuilder.ToMessageBody();
using (var client = new MailKit.Net.Smtp.SmtpClient()) {
client.Connect(_smtpServer, _smtpPort, _enableSsl);
client.Authenticate(_username, _password); // If using GMail this requires turning on LessSecureApps : https://myaccount.google.com/lesssecureapps
if (sendAsync) {
await client.SendAsync(mimeMessage);
}
else {
client.Send(mimeMessage);
}
client.Disconnect(true);
}
}
My end goal is to use a foreach loop on the mimeMessage.To.Add(new MailboxAddress(toAddresses)); so that everyone can receive an email if there is more than 1 email address, if not it can loop once.
Thanks in advance!
In your method, Send(), you are taking in a string for toAddress and then splitting its characters... that wont work. If you want to to use one or more email addresses, you will need to send in email address(es) separated by a delimiter or as a complete list.
Two ways to go about it.
Change the argument from string to List
change your method to take in a List
public async void Send(List<string> toAddress, string subject, string body, bool sendAsync = true)
{
var mimeMessage = new MimeMessage(); // MIME : Multipurpose Internet Mail Extension
mimeMessage.From.Add(new MailboxAddress(_fromAddressTitle, _fromAddress));
toAddress.ForEach(address => mimeMessage.To.Add(new MailboxAddress(address)));
...
if you use this method, you will need to send in the list as well.. not a single email address string.
List<string> toAddress = new List<string>() { "firstEmail", "Second" ...};
_emailSender.Send(toAddress, subject, body);
// You will not be able to do send in single string
_emailSender.Send("firstemail#only.com", subject, body); //Exception no method found.
Send in a delimited list
Always send in comma separated email addresses and translate those to multiple addresses when adding them to To field of your mimeMessage.
public async void Send(string toAddress, string subject, string body, bool sendAsync = true)
{
var mimeMessage = new MimeMessage(); // MIME : Multipurpose Internet Mail Extension
mimeMessage.From.Add(new MailboxAddress(_fromAddressTitle, _fromAddress));
// HERE -> FOREACH string, not char.
foreach (string toAddresses in toAddress.Split(',')) // Split on ,
{
mimeMessage.To.Add(new MailboxAddress(toAddresses));
}
and you will need to use this method the following way...
List<string> toAddress = new List<string>() {"first", "..."};
_emailSender.Send(string.Join(',',toAddress), subject, body);
Is it possible to send an email message in a Windows Universal App for Windows 8.1 and Windows Phone 8.1?
await Launcher.LaunchUriAsync(new Uri("mailto:abc#abc.com?subject=MySubject&body=MyContent"));
With this code line I can send an email, but I want to send a message with attachment.
Since Microsoft missed to add EmailMessage and EmailManager to the Windows Store Apps libraries it seems as if there are only two unsatisfactory solutions: You could use sharing or initiate email sending via the mailto protocol. Here is how I did it:
/// <summary>
/// Initiates sending an e-mail over the default e-mail application by
/// opening a mailto URL with the given data.
/// </summary>
public static async void SendEmailOverMailTo(string recipient, string cc,
string bcc, string subject, string body)
{
if (String.IsNullOrEmpty(recipient))
{
throw new ArgumentException("recipient must not be null or emtpy");
}
if (String.IsNullOrEmpty(subject))
{
throw new ArgumentException("subject must not be null or emtpy");
}
if (String.IsNullOrEmpty(body))
{
throw new ArgumentException("body must not be null or emtpy");
}
// Encode subject and body of the email so that it at least largely
// corresponds to the mailto protocol (that expects a percent encoding
// for certain special characters)
string encodedSubject = WebUtility.UrlEncode(subject).Replace("+", " ");
string encodedBody = WebUtility.UrlEncode(body).Replace("+", " ");
// Create a mailto URI
Uri mailtoUri = new Uri("mailto:" + recipient + "?subject=" +
encodedSubject +
(String.IsNullOrEmpty(cc) == false ? "&cc=" + cc : null) +
(String.IsNullOrEmpty(bcc) == false ? "&bcc=" + bcc : null) +
"&body=" + encodedBody);
// Execute the default application for the mailto protocol
await Launcher.LaunchUriAsync(mailtoUri);
}
Windows Phone 8.1
You could use the following to send email with attachment:
var email = new EmailMessage();
email.To = ...;
email.Body = ...;
email.Attachments.Add( ... );
var ignore = EmailManager.ShowComposeNewEmailAsync(email);
Windows 8.1
On Windows 8.1, unfortunately, there is no way to send email with attachment. The mailto protocol is all you have and it doesn't not officially supports attachment. However, you can add attachment as the following:
mailto:xxx#xxx.com?subject=xxx&body=xxx&attach=C:\path\to\file
or
mailto:xxx#xxx.com?subject=xxx&body=xxx&Attachment=C:\path\to\file
But it is up to the client to decide whether it will handle the attachment or not. See this thread for more detail https://msdn.microsoft.com/en-us/library/aa767737(v=vs.85).aspx
To send emails with attachment You would be needed to use the EmailMessage and EmailManager class.
1. EmailMessage:
The EmailMessage class defines the actual email that will be sent. You can specify the recipients (To , CC , BC) , Subject and the Body of the email .
2. EmailManager:
The EmailManager class is defined in the Windows.ApplicationModel.Email namespace . The EmailManager class provides a static method ShowComposeNewEmailAsync which accepts the EmailMessage as argument . The ShowComposeNewEmailAsync will launch the Compose email Screen with the EmailMessage which allows the users to send an email message.
You can find more reference here windows-phone-8-1-and-windows-runtime-apps-how-to-2-send-emails-with-attachment-in-wp-8-1
On this page: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh871373.aspx
Microsoft supplies a example how to share with your application. Download the source example app: http://go.microsoft.com/fwlink/p/?linkid=231511
Open the solution and add a file: test.txt to the project root.
Then open ShareFiles.xaml.cs and replace the class with:
public sealed partial class ShareText : SDKTemplate.Common.SharePage
{
public ShareText()
{
this.InitializeComponent();
LoadList();
}
List<Windows.Storage.IStorageItem> list { get; set; }
public async void LoadList()
{
var uri = new Uri("ms-appx:///test.txt");
var item = await StorageFile.GetFileFromApplicationUriAsync(uri);
list = new List<IStorageItem>();
list.Add(item);
}
protected override bool GetShareContent(DataRequest request)
{
bool succeeded = false;
string dataPackageText = TextToShare.Text;
if (!String.IsNullOrEmpty(dataPackageText))
{
DataPackage requestData = request.Data;
requestData.Properties.Title = TitleInputBox.Text;
requestData.Properties.Description = DescriptionInputBox.Text; // The description is optional.
requestData.Properties.ContentSourceApplicationLink = ApplicationLink;
requestData.SetText(dataPackageText);
requestData.SetStorageItems(list);
succeeded = true;
}
else
{
request.FailWithDisplayText("Enter the text you would like to share and try again.");
}
return succeeded;
}
}
Might not be the best code, but it helped me :)
I need to create an plain-test email in code. This is required because the information in the email will be read by an application.
I've created the following value in an constant string as setup for my email. These are the fields that I want to be in the e-mail because the application requires them.
public static string TestMail = #"
[Begin Message]
Name = {0}
Phone = {1}
Postalcode = {2}
HomeNumber = {3}
[End message]";
When sending the email using the code below, the application which needs to read information from the email, receives it as following;
=0D=0A [Begin Message]=0D=0A Name =3D nam=
e=0D=0A Phone =3D 0612345678=0D=0A Postalcode =3D =
1234ab=0D=0A HomeNumber =3D 5=0D=0A [End messa=
ge]=0D=0A =20
The code I used to send this email is as following;
var mailBody = String.Format(Constants.TestMail, name, phone, postalCode, homeNumber);
var mail = new MailMessage
{
Subject = Constants.Subject,
Body = mailBody,
IsBodyHtml = false,
};
mail.To.Add(receveiver);
var smtpClient = new SmtpClient();
smtpClient.Send(mail);
This isn't the result I expected and after digging around a bit I found out that the problem lied in the fact that it still seems to be an HTML-email while I need it to be plain-text. While reading about this problem I found this example in VB.net on the internet. So i modified the constant to the one below;
public static string TestMail = #"[Begin message]\r\nName = {0}\r\nPhone = {1}\r\nPostalcode = {2}\r\nHomenumber = {3}\r\n[End message]";
Then I used the following code to create and sent the email to my client (testing in outlook)
var mail = new MailMessage
{
Subject = Constants.Subject,
};
var alternateView = System.Net.Mail.AlternateView.CreateAlternateViewFromString(mailBody, Encoding.ASCII,"text/plain");
mail.AlternateViews.Add(alternateView);
mail.To.Add(receveiver);
var smtpClient = new SmtpClient();
smtpClient.Send(mail);
After running this code i'm receiving an email in my outlook (can't test the application at the moment) containing the content below;
[Start message]\r\nName = John\r\nPhone = 0612345678\r\nPostalcode = 1234ab\r\nHomeNumber = 5\r\n[End Message]
The last result doesn't seem an plain-text email to me. Is it just outlook 2007 having problems to show the email? Or am I still missing something? I hope someone can help me out here and can tell me what's going wrong.
You should remove # character because then it will correctly handle escape characters. If you have # then all escape characters are treated as a plain text instead of new line etc.
I have a situation in ASP.NET C# wherein for example I have the email address hello#gmail.com but I need to have the #gmail.com portion removed for all email input. Please help. Thanks :)
You can use MailAddress Class (System.Net.Mail):
string mailAddress = "hello#gmail.com";
var mail = new MailAddress(mailAddress);
string userName = mail.User; // hello
string host = mail.Host; // gmail.com
string address = mail.Address; // hello#gmail.com
In the case of wrong e-mail address (eg. lack of at sign or more than one) you have to catch FormatException, for example:
string mailAddress = "hello#gmail#";
var mail = new MailAddress(mailAddress); // error: FormatException
If you don't want to verify e-mail address, you can use Split method from string:
string mailAddress = "hello#gmail.com";
char atSign = '#';
string user = mailAddress.Split(atSign)[0]; // hello
string host = mailAddress.Split(atSign)[1]; // gmail.com
email = email.Substring(0, email.IndexOf('#'));
Like this:
new MailAddress(someString).User
If the email address is invalid, this will throw an exception.
If you also need to validate the email address, you should write new MaillAddress(someString) inside of a catch block; this is the best way to validate email addresses in .Net.