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"));
Related
When i used this code, when the email is delivered the list of addresses in bcc is visible, why please?
I use .Net Framework 4.6.2
The code works correctly, it sends the emails but when I check the To: in the email delivered I can see all the recipients that I have included in .Bcc.Add
bcc does not work as microsoft says?
public static bool SendEmails(string[] emailList, string from, string body, string subject, string attachment)
{
var result= false;
MailMessage email = null;
if (emailList!= null && !string.IsNullOrWhiteSpace(from))
{
email = new MailMessage
{
Priority = MailPriority.High,
From = new MailAddress(from),
Subject = subject,
Body = body,
BodyEncoding = Encoding.UTF8,
IsBodyHtml = true,
DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure,
};
if (!string.IsNullOrWhiteSpace(attachment))
{
email.Attachments.Add(new Attachment(attachment));
}
var smtp = new SmtpClient
{
Host = host,
Credentials =new System.Net.NetworkCredential("user","pass"),
EnableSsl = Convert.ToBoolean(ConfigurationManager.AppSettings["enablessl"]),
Port = int.Parse(ConfigurationManager.AppSettings["port"])
};
if (emailList.Count() > 0)
{
foreach (string email in emailList)
{
email.Bcc.Add(new MailAddress(email));
}
}
smtp.Send(email);
result= true;
}
return restul;
}
Apparently, it is necessary to include an email in emai.To.Add("anymail#anyhost.com") before starting the loop where the addresses are loaded in bcc, I don't know if this has any other consequences, but that's how it works. Email addresses are no longer displayed in the To: of the delivered message.
I am using Rotativa to convert my view to pdf. I would like to send that generated pdf as an email attachment (without having to download it first to disk). I've been following a bunch of tutorials to do this but I just keep going round in circles. I would much appreciate any help I can get.
public async Task<IActionResult>SomeReport()
{
...
return new ViewAsPdf (report)
}
return view();
MemoryStream memoryStream = new MemoryStream();
MimeMessage msg = new MimeMessage();
MailboxAddress from = new MailboxAddress ("Name", "emailAddress")
msg.From.Add(from);
MailboxAddress to = new MailboxAddress ("Name", "emailAddress")
msg.From.Add(to);
BodyBuilder bd = new BodyBuilder();
bb.HtmlBody ="some text";
bb.Attachments.Add("attachmentName", new MemoryStream());
msg.Body = bb.ToMessageBody();
SmtpClient smtp = new SmtpClient();
smtp.Connect("smtp.gmail.com",465, true);
smtp.Authenticate("emailAddress", "Pwd");
smtp.Send(msg);
smtp.Disconnect(true);
smtp.Dispose();
Edit
Parent View from which Email is sent
#Model MyProject.Models.EntityViewModel
<a asp-action= "SendPdfMail" asp-controller ="Student" asp-route-id = "#Model.Student.StudentId">Email</a>
...
SendPdfMail action in Student Controller
public async Task<IActionResult> SendPdfMail(string id)
{
var student = await context.Student. Where(s => s.StudentId == id);
if (student != null)
{
...
var viewAsPdf = new ViewAsPdf("MyPdfView", new{route = id})
{
Model = new EntityViewModel(),
FileName = PdfFileName,
...
}
}
};
Complete answer using Rotativa.AspNetCore. Code is developed in VS 2019, Core 3.1, Rotativa.AspNetCore 1.1.1.
Nuget
Install-package Rotativa.AspNetCore
Sample controller
public class SendPdfController : ControllerBase
{
private const string PdfFileName = "test.pdf";
private readonly SmtpClient _smtpClient;
public SendPdfController(SmtpClient smtpClient)
{
_smtpClient = smtpClient;
}
[HttpGet("SendPdfMail")] // https://localhost:5001/SendPdfMail
public async Task<IActionResult> SendPdfMail()
{
using var mailMessage = new MailMessage();
mailMessage.To.Add(new MailAddress("a#b.c"));
mailMessage.From = new MailAddress("c#d.e");
mailMessage.Subject = "mail subject here";
var viewAsPdf = new ViewAsPdf("view name", <YOUR MODEL HERE>)
{
FileName = PdfFileName,
PageSize = Size.A4,
PageMargins = { Left = 1, Right = 1 }
};
var pdfBytes = await viewAsPdf.BuildFile(ControllerContext);
using var attachment = new Attachment(new MemoryStream(pdfBytes), PdfFileName);
mailMessage.Attachments.Add(attachment);
_smtpClient.Send(mailMessage); // _smtpClient will be disposed by container
return new OkResult();
}
}
Options class
public class SmtpOptions
{
public string Host { get; set; }
public int Port { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
In Startup#ConfigureServices
services.Configure<SmtpOptions>(Configuration.GetSection("Smtp"));
// SmtpClient is not thread-safe, hence transient
services.AddTransient(provider =>
{
var smtpOptions = provider.GetService<IOptions<SmtpOptions>>().Value;
return new SmtpClient(smtpOptions.Host, smtpOptions.Port)
{
// Credentials and EnableSsl here when required
};
});
appsettings.json
{
"Smtp": {
"Host": "SMTP HOST HERE",
"Port": PORT NUMBER HERE,
"Username": "USERNAME HERE",
"Password": "PASSWORD HERE"
}
}
There's not quite enough to go on, but you need something like this:
MimeMessage msg = new MimeMessage();
MailboxAddress from = new MailboxAddress ("Name", "emailAddress");
msg.From.Add(from);
MailboxAddress to = new MailboxAddress ("Name", "emailAddress");
msg.To.Add(to);
BodyBuilder bb = new BodyBuilder();
bb.HtmlBody ="some text";
using (var wc = new WebClient())
{
bb.Attachments.Add("attachmentName",wc.DownloadData("Url for your view goes here"));
}
msg.Body = bb.ToMessageBody();
using (var smtp = new SmtpClient())
{
smtp.Connect("smtp.gmail.com",465, true);
smtp.Authenticate("emailAddress", "Pwd");
smtp.Send(msg);
smtp.Disconnect(true);
}
Notice this adds the attachment before calling .ToMessageBody(), as well as fixing at least four basic typos.
But I doubt this will be enough... I suspect ViewAsPdf() needs more context than you get from a single DownloadData() request, and you'll need to go back to the drawing board to be able to provide that context, but this at least will help push you in the right direction.
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.
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
}
This question already has answers here:
How to send HTML-formatted email? [duplicate]
(3 answers)
Closed 5 years ago.
I am calling a function that sends an email in my asp.net mvc project and I want the body to be able to format as html
Here is my function that sends the email :
private void EnvoieCourriel(string adrCourriel, string text, string object, string envoyeur, Attachment atache)
{
SmtpClient smtp = new SmtpClient();
MailMessage msg = new MailMessage
{
From = new MailAddress(envoyeur),
Subject = object,
Body = text,
};
if (atache != null)
msg.Attachments.Add(atache);
msg.To.Add(adrCourriel);
smtp.Send(msg);
return;
}
The email is sent and it works like a charm, but It just shows plain html so I was wondering an argument in my instanciation of MailMessage
You just need to add the parameter IsBodyHtml to your instanciation of the MailMessage like this :
private bool EnvoieCourriel(string adrCourriel, string corps, string objet, string envoyeur, Attachment atache)
{
SmtpClient smtp = new SmtpClient();
MailMessage msg = new MailMessage
{
From = new MailAddress(envoyeur),
Subject = objet,
Body = corps,
IsBodyHtml = true
};
if (atache != null)
msg.Attachments.Add(atache);
try
{
msg.To.Add(adrCourriel);
smtp.Send(msg);
}
catch(Exception e)
{
var erreur = e.Message;
return false;
}
return true;
}
I also added a try catch because if there is a problem when trying to send the message you can show an error or just know that the email was not sent without making the application crash
I think you are looking for IsBodyHtml.
private void EnvoieCourriel(string adrCourriel, string text, string object, string envoyeur, Attachment atache)
{
SmtpClient smtp = new SmtpClient();
MailMessage msg = new MailMessage
{
From = new MailAddress(envoyeur),
Subject = object,
Body = text,
IsBodyHtml = true
};
if (atache != null)
msg.Attachments.Add(atache);
msg.To.Add(adrCourriel);
smtp.Send(msg);
return;
}