I'm sending emails with asp.net core 2.0 like this
public string EmailServiceSend(string body, string subject = null, string to = null,
string multipleRecipients = null, string attachmentUrl = null, string smtpClient = null,
string userCredential = null, string userPassword = null, string from = null, bool template = false,
string templateRoute = null)
{
try
{
SmtpClient client = new SmtpClient("mysmtpserver");
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("username", "password");
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress("whoever#me.com");
mailMessage.To.Add("receiver#me.com");
mailMessage.Body = body;
mailMessage.Subject = subject;
client.Send(mailMessage);
}
catch(Exception ex)
{
ex.Message.ToString();
}
return "Email sended"
}
I want to know, how can I create a list of email domains to block and send an error message. For example I want to block this domains:
0-mail.com
0815.ru
0clickemail.com
0wnd.net
and then send a response into my return statement for example:
if(listofblockmails == true){
return "You can't add this email domain, change it please"
}
How can I achieve that? Regards
Try using Linq:
Lets say you have this List:
List<string> listofblockmails = new List<string>();
listofblockmails.Add("0-mail.com");
listofblockmails.Add("0815.ru");
listofblockmails.Add("0clickemail.com");
listofblockmails.Add("0wnd.net");
You can do as below:
if (listofblockmails.Contains("emailToBeChecked.com"))
{
//return "You can't add this email domain, change it please";
}
else
{
//send
//return "Email sended";
}
And let Garbage collector do the disposal.
You can simply parse the email address and get the domain part, and compare againist a list of bad domains. If the domain is present in your bad domain list, return messge.
You can create a method like this.
private bool IsGoodDomain(string email)
{
if (string.IsNullOrEmpty(email))
return false;
var badDomains = new List<string>
{
"0815.ru",
"0wnd.net"
};
var r = email.Split('#');
if (!r.Any()) return false;
var domainName = r.Last();
return !badDomains.Contains(domainName, StringComparer.InvariantCultureIgnoreCase);
}
and call this method in your other method
if(IsGoodDomain(someEmailAddressVariable))
{
//contnue sending
}
else
{
// return the error message
}
Related
I have the below method in C#. How do I write unit tests for the parameters with Moq?. I wanted to make sure the email sender address, cc, emailbody, senderaccountpassword are correct
Not sure what to mock and what should be the object.
public string SendEmail(string emailNotificationSender, string senderAccountPassword, string emailCcList,
string emailBody, string emailSubject, List<string> toReceipients)
{
try
{
ExchangeService exchangeService = new ExchangeService(ExchangeVersion.Exchange2016);
exchangeService.Credentials = new WebCredentials(emailNotificationSender, senderAccountPassword);
exchangeService.AutodiscoverUrl(emailNotificationSender, RedirectionUrlValidationCallback);
EmailMessage email = new EmailMessage(exchangeService);
email.ToRecipients.AddRange(toReceipients);
List<string> EmailNotificationCcList = new List<string>();
EmailNotificationCcList = emailCcList.Split(';').ToList();
email.CcRecipients.AddRange(EmailNotificationCcList);
email.Subject = emailSubject;
email.Body = new MessageBody(emailBody.ToString());
email.Send();
//return System.Threading.Tasks.Task.FromResult("Success");
return "Success";
}
catch (Exception exception)
{
OnError(new ErrorRecordEventArgs
{
ErrorSource = "ExchangeDataStore::ExecuteQuery()",
//DataSource = dataSource,
//DataSourceType = dataSourceType,
Exception = exception
});
}
return default;
}
public static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
// The default for the validation callback is to reject the URL.
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
// Validate the contents of the redirection URL. In this simple validation
// callback, the redirection URL is considered valid if it is using HTTPS
// to encrypt the authentication credentials.
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
I use this to send mails, I've defined some package variables which contains values:
public MailProperties(ScriptObjectModel dts)
{
if (
!string.IsNullOrEmpty((string)dts.Variables["$Package::mailFrom"].Value) &&
!string.IsNullOrEmpty((string)dts.Variables["$Package::mailTo"].Value) &&
!string.IsNullOrEmpty((string)dts.Variables["$Package::mailPwd"].GetSensitiveValue()) &&
!string.IsNullOrEmpty((string)dts.Variables["$Package::mailSmtp"].Value) &&
!string.IsNullOrEmpty((string)dts.Variables["$Package::mailPort"].Value)
)
{
fromMail = (string)dts.Variables["$Package::mailFrom"].Value;
toMail = (string)dts.Variables["$Package::mailTo"].Value;
bccMail = (string)dts.Variables["$Package::mailBcc"].Value;
accountPassword = (string)dts.Variables["$Package::mailPwd"].GetSensitiveValue();
accountSmtp = (string)dts.Variables["$Package::mailSmtp"].Value;
accountSmtpPort = (string)dts.Variables["$Package::mailPort"].Value;
useSSL = (bool)dts.Variables["$Package::useSSL"].Value;
pathAttachment = new List<string>();
pathAttachment.Add((string)dts.Variables["User::pathFileReject"].Value);
pathAttachment.Add((string)dts.Variables["User::pathFileReject2"].Value);
}
else
{
throw new Exception("error text...");
}
}
I need to send mail to more people, so I set mailTo with mail1#gmail.com, mailBcc as mail2#gmail.com and it works, but if I set mailBcc as "mail2#gmail.com, mail3#gmail.com" or "mail2#gmail.com; mail3#gmail.com" it doesn't work, how I can do that?
EDIT: this is the sendMail function
public static void sendMail(MailProperties mailProperties, ReportETL reportETL)
{
MimeMessage message = new MimeMessage();
message.From.Add(new MailboxAddress("text..", mailProperties.fromMail));
message.To.Add(new MailboxAddress(mailProperties.toMail));
message.Subject = "text...";
if (!string.IsNullOrEmpty(mailProperties.bccMail))
{
message.Bcc.Add(new MailboxAddress(mailProperties.bccMail));
}
BodyBuilder bodyBuilder = new BodyBuilder();
bodyBuilder.HtmlBody = ReportETLService.getHtmlFromReporETL(reportETL);
mailProperties.pathAttachment.Where(x => File.Exists(x)).ToList().ForEach(y => bodyBuilder.Attachments.Add(y));
message.Body = bodyBuilder.ToMessageBody();
try
{
SmtpClient smtpClient = new SmtpClient();
smtpClient.Connect(mailProperties.accountSmtp, int.Parse(mailProperties.accountSmtpPort), mailProperties.useSSL);
smtpClient.Authenticate(mailProperties.fromMail, mailProperties.accountPassword);
smtpClient.Send(message);
smtpClient.Disconnect(true);
}
catch (Exception e) { throw new Exception("text... " + e.Message); }
}
according to documentation message.To is list type.So you can add more adress like this.
InternetAddressList list = new InternetAddressList();
list.add(adress1)
list.add(adress2)
list.add(adress3)
list.add(adress4)
message.To.AddRange(list);
Instead of using BCC (which would be an option, but has the problem of max count) just iterate over all mail addresses and send one for each recipient. (Not to fast or you get other problems)
This way it should be "easier" to spot mails that will not get delivered.
Well, assuming that your toMail, ccMail, and bccMail properties are just strings and not lists of strings, you could do something like this:
InternetAddressList list;
if (!string.IsNullOrEmpty(mailProperties.toMail) && InternetAddressList.TryParse (mailProperties.toMail, out list))
message.To.AddRange(list);
if (!string.IsNullOrEmpty(mailProperties.ccMail) && InternetAddressList.TryParse (mailProperties.ccMail, out list))
message.Cc.AddRange(list);
if (!string.IsNullOrEmpty(mailProperties.bccMail) && InternetAddressList.TryParse (mailProperties.bccMail, out list))
message.Bcc.AddRange(list);
I am using NetCore.MailKit NuGet package to help me send an email which contains a link to confirm their email when the user registers. I have followed the steps on their Github page but, I am getting an ArgumentNullException for the address, even though I have set the sending address.
The error:
ArgumentNullException: Value cannot be null. (Parameter 'address')
MimeKit.MailboxAddress..ctor(Encoding encoding, string name, string address)
The above error occurs when is send the email in my controller using IEmailService:
_EmailService.Send("usersemail#gmail.com", "subject", "message body");
This is my appsettings.json configuration:
"EmailConfiguration": {
"Server": "smtp.gmail.com",
"Port": 587,
"SenderName": "name",
"SenderEmail": "mygmail#gmail.com",
"SenderPassword": "My gmail password"
}
This is my setup in startup.cs
services.AddMailKit(optionBuilder =>
{
optionBuilder.UseMailKit(new MailKitOptions()
{
//get options from sercets.json
Server = Configuration["Server"],
Port = Convert.ToInt32(Configuration["Port"]),
SenderName = Configuration["SenderName"],
SenderEmail = Configuration["SenderEmail"],
Account = Configuration["SenderEmail"],
Password = Configuration["SenderPassword"],
Security = true
});
});
Below is the code for EmailService:
public void Send(string mailTo, string subject, string message, bool isHtml = false)
{
SendEmail(mailTo, null, null, subject, message, Encoding.UTF8, isHtml);
}
private void SendEmail(string mailTo, string mailCc, string mailBcc, string subject, string message, Encoding encoding, bool isHtml)
{
var _to = new string[0];
var _cc = new string[0];
var _bcc = new string[0];
if (!string.IsNullOrEmpty(mailTo))
_to = mailTo.Split(',').Select(x => x.Trim()).ToArray();
if (!string.IsNullOrEmpty(mailCc))
_cc = mailCc.Split(',').Select(x => x.Trim()).ToArray();
if (!string.IsNullOrEmpty(mailBcc))
_bcc = mailBcc.Split(',').Select(x => x.Trim()).ToArray();
Check.Argument.IsNotEmpty(_to, nameof(mailTo));
Check.Argument.IsNotEmpty(message, nameof(message));
var mimeMessage = new MimeMessage();
//add mail from
mimeMessage.From.Add(new MailboxAddress(_MailKitProvider.Options.SenderName, _MailKitProvider.Options.SenderEmail));
//add mail to
foreach (var to in _to)
{
mimeMessage.To.Add(MailboxAddress.Parse(to));
}
//add mail cc
foreach (var cc in _cc)
{
mimeMessage.Cc.Add(MailboxAddress.Parse(cc));
}
//add mail bcc
foreach (var bcc in _bcc)
{
mimeMessage.Bcc.Add(MailboxAddress.Parse(bcc));
}
//add subject
mimeMessage.Subject = subject;
//add email body
TextPart body = null;
if (isHtml)
{
body = new TextPart(TextFormat.Html);
}
else
{
body = new TextPart(TextFormat.Text);
}
//set email encoding
body.SetText(encoding, message);
//set email body
mimeMessage.Body = body;
using (var client = _MailKitProvider.SmtpClient)
{
client.Send(mimeMessage);
}
}
As you can see I have set everything, am I missing something here? why is address null at MimeKit.MailboxAddress()?
You seem to be not loading your configuration settings correctly. I suspect the failing line in your code is
//add mail from
mimeMessage.From.Add(new MailboxAddress(_MailKitProvider.Options.SenderName, _MailKitProvider.Options.SenderEmail));
The Options are all null, which causes the exception.
When you load the settings from a configuration file you need to prepend the section name to the variables. E.G.
services.AddMailKit(optionBuilder =>
{
optionBuilder.UseMailKit(new MailKitOptions()
{
//get options from sercets.json
Server = Configuration["EmailConfiguration:Server"],
Port = Convert.ToInt32(Configuration["EmailConfiguration:Port"]),
SenderName = Configuration["EmailConfiguration:SenderName"],
SenderEmail = Configuration["EmailConfiguration:SenderEmail"],
Account = Configuration["EmailConfiguration:SenderEmail"],
Password = Configuration["EmailConfiguration:SenderPassword"],
Security = true
});
});
My guess is that the exception is being thrown on the following line:
mimeMessage.From.Add(new MailboxAddress(_MailKitProvider.Options.SenderName, _MailKitProvider.Options.SenderEmail));
This means that _MailKitProvider.Options.SenderEmail is null.
I know you expect these values to be loaded correctly from your appsettings.json file, but seemingly, they are not being loaded for some reason.
After sending an email the logo is not displayed in Outlook but it works in Gmail.
I found that in the inspect element that the image src is changed into blockedimagesrc
In my Controller :
var NotifyCompany = new NotifyCompany()
{
Email = model.regE,
EmailTo = contact.GetPropertyValue<string>("email"),
DateRegistered = DateTime.UtcNow
};
EmailHelpers.SendEmail(NotifyCompany, "NotifyCompany", "New Client Registered");
Helpers :
public static ActionResponse SendEmail(IEmail model, string emailTemplate, string subject, List<HttpPostedFileBase> files = null)
{
try
{
var template =
System.IO.File.ReadAllText(HttpContext.Current.Server.MapPath(string.Format("~/Templates/{0}.cshtml", emailTemplate)));
var body = Razor.Parse(template, model);
var attachments = new List<Attachment>();
if (files != null && files.Any())
{
foreach (var file in files)
{
var att = new Attachment(file.InputStream, file.FileName);
attachments.Add(att);
}
}
var email = Email
.From(ConfigurationManager.AppSettings["Email:From"], "myWebsiteEmail")
.To(model.EmailTo)
.Subject(subject)
.Attach(attachments)
.Body(body).BodyAsHtml();
email.Send();
return new ActionResponse()
{
Success = true
};
}
catch (Exception ex)
{
return new ActionResponse()
{
Success = false,
ErrorMessage = ex.Message
};
}
}
In my Email Template :
<img src="/mysite.com/image/logo.png"/>
Any help would be appreciated.
Outlook web access will block any images by default - only if the user chooses to display/download images these will be displayed/downloaded. I am not sure if it is possible to adjust the default behavior by using office 365 admincenter or the OWA settings.
Some time ago it was possible to work around this by using it as a background image inside a table>tr>td cell background-image css property.
EDIT
Checked a recent project of myself, where we are sending notification mails about tickets. The site logo is displayed correctly in outlook/owa - without adding the recipient to the trusted list:
using (MailMessage mm = new MailMessage(sender, header.RecipientAddress, header.Subject, header.Body))
{
mm.Body = header.Body;
mm.BodyEncoding = Encoding.UTF8;
mm.DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure;
mm.Priority = priority == IntMailPriority.High ? MailPriority.High : MailPriority.Normal;
mm.IsBodyHtml = bodyIsHtml;
// logo
if (bodyIsHtml)
{
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(header.Body, Encoding.UTF8, "text/html");
string logoPath = $"{AppDomain.CurrentDomain.BaseDirectory}\\images\\logo_XXX.png";
LinkedResource siteLogo = new LinkedResource(logoPath)
{
ContentId = "logoId"
};
htmlView.LinkedResources.Add(siteLogo);
mm.AlternateViews.Add(htmlView);
}
// create smtpclient
SmtpClient smtpClient = new SmtpClient(smtpSettings.ServerAddress, smtpSettings.Port)
{
Timeout = 30000,
DeliveryMethod = SmtpDeliveryMethod.Network
};
// set relevant smtpclient settings
if (smtpSettings.UseTlsSsl)
{
smtpClient.EnableSsl = true;
// needed for invalid certificates
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
}
if (smtpSettings.UseAuth)
{
smtpClient.UseDefaultCredentials = false;
NetworkCredential smtpAuth = new NetworkCredential { UserName = smtpSettings.Username, Password = smtpSettings.Password };
smtpClient.Credentials = smtpAuth;
}
smtpClient.Timeout = smtpSettings.SendingTimeout * 1000;
// finally sent mail \o/ :)
try
{
smtpClient.Send(mm);
}
catch (SmtpException exc)
{
throw new ProgramException(exc, exc.Message);
}
catch (InvalidOperationException exc)
{
throw new ProgramException(exc, exc.Message);
}
catch (AuthenticationException exc)
{
throw new ProgramException(exc, exc.Message);
}
}
Afterwards the logo is referred to as
<IMG alt="Intex Logo" src="cid:logoId">
inside the generated html.
I'm going through my app, trying to clean up some code that sends e-mails. I started creating my own emailer wrapper class, but then I figured that there must be a standard emailer class out there somewhere. I've done some searching, but couldn't find anything.
Also, is there a code base for stuff like this anywhere?
EDIT: Sorry, let me clarify.
I don't want to have this in my code any time I need to send an e-mail:
System.Web.Mail.MailMessage message=new System.Web.Mail.MailMessage();
message.From="from e-mail";
message.To="to e-mail";
message.Subject="Message Subject";
message.Body="Message Body";
System.Web.Mail.SmtpMail.SmtpServer="SMTP Server Address";
System.Web.Mail.SmtpMail.Send(message);
I created a class named Emailer, that contains functions like:
SendEmail(string to, string from, string body)
SendEmail(string to, string from, string body, bool isHtml)
And so I can just put this a single line in my code to send an e-mail:
Emailer.SendEmail("name#site.com", "name2#site.com", "My e-mail", false);
I mean, it's not too complex, but I figured there was a standard, accepted solution out there.
Something like this?
using System;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using MailMessage=System.Net.Mail.MailMessage;
class CTEmailSender
{
string MailSmtpHost { get; set; }
int MailSmtpPort { get; set; }
string MailSmtpUsername { get; set; }
string MailSmtpPassword { get; set; }
string MailFrom { get; set; }
public bool SendEmail(string to, string subject, string body)
{
MailMessage mail = new MailMessage(MailFrom, to, subject, body);
var alternameView = AlternateView.CreateAlternateViewFromString(body, new ContentType("text/html"));
mail.AlternateViews.Add(alternameView);
var smtpClient = new SmtpClient(MailSmtpHost, MailSmtpPort);
smtpClient.Credentials = new NetworkCredential(MailSmtpUsername, MailSmtpPassword);
try
{
smtpClient.Send(mail);
}
catch (Exception e)
{
//Log error here
return false;
}
return true;
}
}
Maybe you're looking for SmtpClient?
I use a generic class made out of this old Stack Overflow Answer.
Try this.
public bool SendEmail(MailAddress toAddress, string subject, string body)
{
MailAddress fromAddress = new MailAddress("pull from db or web.config", "pull from db or web.config");
string fromPassword = "pull from db or config and decrypt";
string smtpHost = "pull from db or web.config";
int smtpPort = 587;//gmail port
try
{
var smtp = new SmtpClient
{
Host = smtpHost,
Port = smtpPort,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
};
using (var message = new MailMessage(fromAddress, toAddress)
{
Subject = subject,
Body = body,
IsBodyHtml = true
})
{
smtp.Send(message);
}
return true;
}
catch (Exception err)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(err);
return false;
}
}
This is a snippet from one of my projects. It's a little more feature-packed than some of the other implementations.
Using this function allows you to create an email with:
Tokens that can be replaced with actual values at runtime
Emails that contain both a text and HTML view
public MailMessage createMailMessage(string toAddress, string fromAddress, string subject, string template)
{
// Validate arguments here...
// If your template contains any of the following {tokens}
// they will be replaced with the values you set here.
var replacementDictionary = new ListDictionary
{
// Replace with your own list of values
{ "{first}", "Pull from db or config" },
{ "{last}", "Pull from db or config" }
};
// Create a text view and HTML view (both will be in the same email)
// This snippet assumes you are using ASP.NET (works w/MVC)
// if not, replace HostingEnvironment.MapPath with your own path.
var mailDefinition = new MailDefinition { BodyFileName = HostingEnvironment.MapPath(template + ".txt"), IsBodyHtml = false };
var htmlMailDefinition = new MailDefinition { BodyFileName = HostingEnvironment.MapPath(template + ".htm"), IsBodyHtml = true };
MailMessage htmlMessage = htmlMailDefinition.CreateMailMessage(email, replacementDictionary, new Control());
MailMessage textMessage = mailDefinition.CreateMailMessage(email, replacementDictionary, new Control());
AlternateView plainView = AlternateView.CreateAlternateViewFromString(textMessage.Body, null, "text/plain");
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(htmlMessage.Body, null, "text/html");
var message = new MailMessage { From = new MailAddress(from) };
message.To.Add(new MailAddress(toAddress));
message.Subject = subject;
message.AlternateViews.Add(plainView);
message.AlternateViews.Add(htmlView);
return message;
}
Assuming you have your Web.config set up for NetMail, you can call this method from a helper method like so:
public bool SendEmail(MailMessage email)
{
var client = new SmtpClient();
try
{
client.Send(message);
}
catch (Exception e)
{
return false;
}
return true;
}
SendMail(createMailMessage("to#email.com", "from#email.com", "Subject", "~/Path/Template"));