How do I properly dispose SMTP object? - c#

I have a loop where if you dropped a file into a folder, it would email you on success/failure. I tried the 'using' statement which implements Dispose() automatically.
I also tried a 'try/finally' statement (recommended here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement . Both of which gave me this error:
Cannot access a disposed object. Object name 'system.net.mail.smtpclient'
Attempt 1:
private int _disposed;
private readonly string _fromEmail;
private readonly SmtpClient _client;
public Emailer()
{
_disposed = 0;
_fromEmail = "email";
_client = new SmtpClient("domain-com.mail.protection.outlook.com", 25)
{
EnableSsl = true,
Credentials = new NetworkCredential(_fromEmail, "password")
};
}
public async Task SendEmailAsync(IList<string> to, string subject, string body)
{
using (MailMessage mail = new MailMessage())
{
mail.From = new MailAddress(_fromEmail);
foreach (string toEmail in to)
mail.To.Add(toEmail);
mail.Subject = subject;
mail.Body = body;
mail.IsBodyHtml = true;
using (SmtpClient smtp = _client)
{
smtp.Credentials = _client.Credentials;
smtp.EnableSsl = _client.EnableSsl;
await smtp.SendMailAsync(mail);
}
}
}
Attempt 2:
private int _disposed;
private readonly string _fromEmail;
private readonly SmtpClient _client;
public Emailer()
{
_disposed = 0;
_fromEmail = "email";
_client = new SmtpClient("domain-com.mail.protection.outlook.com", 25)
{
EnableSsl = true,
Credentials = new NetworkCredential(_fromEmail, "password")
};
}
public async Task SendEmailAsync(IList<string> to, string subject, string body)
{
using (MailMessage mail = new MailMessage())
{
mail.From = new MailAddress(_fromEmail);
foreach (string toEmail in to)
mail.To.Add(toEmail);
mail.Subject = subject;
mail.Body = body;
mail.IsBodyHtml = true;
try
{
SmtpClient smtp = _client;
smtp.Credentials = _client.Credentials;
smtp.EnableSsl = _client.EnableSsl;
await smtp.SendMailAsync(mail);
}
finally
{
Dispose();
}
}
}
My Dispose() Method
public void Dispose()
{
if (Interlocked.CompareExchange(ref _disposed, 1, 0) != 0)
return;
_client.Dispose();
}
}
}

You are disposing a Smtp object on your first call. You need to expose method to dispose smtp object and once your loop gets complete call this method to dispose your smtp object and get rid of your using statement.
public void DisposeSMTPClient()
{
_client.Dispose();
}
public async Task SendEmailAsync(IList<string> to, string subject, string body)
{
var mail = new MailMessage();
mail.From = new MailAddress(_fromEmail);
foreach (string toEmail in to)
mail.To.Add(toEmail);
mail.Subject = subject;
mail.Body = body;
mail.IsBodyHtml = true;
await _client.SendMailAsync(mail);
}
Call DisposeSMTPClient this function after your loops end

My problem was using 2 using statements.
I fixed it by using a try catch block for sending the email and the original using statement along with implementing the IDisposable class.
using (MailMessage mail = new MailMessage())
{
mail.From = new MailAddress(_fromEmail);
foreach (string toEmail in to)
mail.To.Add(toEmail);
mail.Subject = subject;
mail.Body = body;
mail.IsBodyHtml = true;
//mail.Attachments.Add(new Attachment("D:\\TestFile.txt"));//--Uncomment this to send any attachment
try
{
SmtpClient smtp = _client;
smtp.Credentials = _client.Credentials;
smtp.EnableSsl = _client.EnableSsl;
await smtp.SendMailAsync(mail);
}
catch
{ }
}

Related

The smtp service is not working but there is no errors .net6

I'm trying to implement a mail service to use it with sending reset password email, I tried to use Gmail and it doesn't work so I switched to outlook but it still not working. Can anybody help? Thanks
private SmtpClient _client;
public StringBuilder _body;
public EmailService()
{
_body = new StringBuilder();
_client = new SmtpClient();
}
public void Dispose()
{
_body.Clear();
_client.Dispose();
}
public async Task<bool> SendEmailAsync(string fullname, string receiverEmail, string subject)
{
try
{
MailMessage mail = new MailMessage();
mail.To.Add(receiverEmail);
mail.From = new MailAddress("testmoenergy#outlook.com", "Aljawhara", Encoding.UTF8);
mail.Subject = subject;
mail.Body = _body.ToString();
mail.IsBodyHtml = true;
mail.Priority = MailPriority.High;
_client.Host = "smtp.outlook.com";
_client.Port = 587;
_client.UseDefaultCredentials = false;
_client.Credentials = new NetworkCredential("testmoenergy#outlook.com", "test******");
_client.EnableSsl = true;
await _client.SendMailAsync(mail);
return true;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}
}
The Gmail oauth is not allowing users to send mail from 1-may 2022. you have to create a auth key from you gmail account and use it as password.
string username = "yourmailID";
string password = "yourauthcode";
ICredentialsByHost credentials = new NetworkCredential(username, password);
SmtpClient smtpClient = new SmtpClient()
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
Credentials = credentials
};
MailMessage mail = new MailMessage();
mail.From = new MailAddress(username);
mail.To.Add(username);
mail.Subject = subject;
mail.Body = body;
smtpClient.Send(mail);
for generate auth code
In gmail go to you account settings--> security-->enable two step verfication to ON -->app passwords--> give you custom app name and click generate .
This will give your auth code.

Asynchronous code to send email notification fails to send email occasionally

My web application in production sometimes fails to send an order email notification. I have never experienced the issue in the test environment.
I do not understand why it is behaving like this way. Could you please guide me on what is causing the issue?
Below is my code:
public async Task SendEmail(int alertID, string body, string subject, List<string> ccemailToUserList)
{
try
{
using (var dbcontext = new MyDbContext())
{
List<string> emailRecipients = new List<string>();
Alert emailAlert = new Alert();
emailAlert = dbcontext.Alerts.FirstOrDefault(x => x.ID == alertID);
body = body.Replace("[[ordertype]]", emailAlert.Description);
MailMessage mail = new MailMessage();
var mailFrom = ConfigurationManager.AppSettings["SMTPFrom"].ToString();
mail.From = new MailAddress(mailFrom);
mail.To.Add(emailAlert.Recipients);
foreach (var ccEmail in ccemailToUserList)
{
mail.CC.Add(ccEmail);
}
SmtpClient client = new SmtpClient();
client.Port = 25;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Host = ConfigurationManager.AppSettings["SMTP"].ToString();
mail.Subject = emailAlert.Description+ " - " + subject;
mail.Body = body;
mail.IsBodyHtml = true;
await client.SendMailAsync(mail);
}
}
catch (Exception ex)
{
ErrorService.LogError(ex, "Email Error");
}
}

How send email async in MVC

In my system, I need send lot of emails. But, if I wait to send all the emails, the page gets too slow. I have tried to create an async class - but, the class starts and dies before the emails are even sent.
public class NotificationManager
{
public void SendNotification(NotificationData data)
{
data.MailTo = new WorkflowManager().GetEmailNotification((StatusType)data.Issue.StatusID, data.Issue.IssueId);
Task.Factory.StartNew(() =>
{
new MailManager().SendMessage(data);
});
}
}
class MailManager
{
static ILog log = log4net.LogManager.GetLogger(typeof(MailManager));
public static void SendMessage(Models.Extensions.NotificationData data)
{
var domain = string.Format("{0}/{1}", HttpContext.Current.Request.Url.AbsoluteUri.Replace("Edit", "IssueDetail"), data.Issue.IssueCode);
string type = new TypeManager().GetTypeById(data.Issue.IssueTypeID).Name;
string status = new StatusManager().GetStatusById(data.Issue.IssueTypeID).Name;
var body = string.Format("<h2>[{3}]</h2><br/>{0}<br/><br/><a href='{1}'>Issue</a><br/>[Ticket Number: {2}]",
data.Issue.Description, domain, data.Issue.IssueCode, type);
var subject = string.Format("[{0}] {1}", status, data.Issue.Summary);
SendEmailAwaitable(data.MailTo, subject, body);
log.Error("End Send Email Async");
}
private async Task<bool> SendEmailAwaitable(List<MailAddress> To, string Subject, string Body, bool isBodyHtml = true)
{
Settings s = new Settings();
MailMessage message = new MailMessage();
MailAddress fromAddress = new MailAddress(s.Email, s.EmailDisplayName);
SmtpClient smtpClient = new SmtpClient();
NetworkCredential basicCredential = new NetworkCredential(s.EmailUserName, s.EmailPassword);
string userToken = Subject;
smtpClient.Host = s.EmailServer;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = basicCredential;
message.From = fromAddress;
message.Subject = Subject;
message.IsBodyHtml = isBodyHtml;
message.Body = Body;
foreach (var item in To)
{
userToken += ":To: " + item.Address;
message.To.Add(item);
}
smtpClient.SendCompleted += smtpClient_SendCompleted;
smtpClient.SendAsync(message, null);
await Task.Yield();
return true;
}

How to request operating system to send email in c#?

How to request the operating system to send email with a specific subject, body and attachment? The OS should launch the default email client with the fields pre-loaded?
Specifically what API functions are available in C#.net?
Since you want the outlook to send the email, substitute the port number and host with that of the outlook.
To Open Outlook with pre-loaded fields:
using System.Diagnostics;
// ...
Process.Start(String.Format("mailto:{0}?subject={1}&cc={2}&bcc={3}&body={4}", address, subject, cc, bcc, body))
To send the Email directly :
using System.Net;
using System.Net.Mail;
// ...
var fromAddress = new MailAddress("from#gmail.com", "From Name");
var toAddress = new MailAddress("to#example.com", "To Name");
const string fromPassword = "fromPassword";
const string subject = "Subject";
const string body = "Body";
var smtp = new SmtpClient {
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
};
using(var message = new MailMessage(fromAddress, toAddress) {
Subject = subject,
Body = body
})
{
smtp.Send(message);
}
This is a simple adapter for system SmtpClient that will simplify yours tests.
public class SmtpClientAdapter : ISmtpClient
{
private bool disposed;
private SmtpClient smtpClient = new SmtpClient();
public SendResult Send(MailMessage message)
{
if (disposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
try
{
smtpClient.Send(message);
return SendResult.Successful;
}
catch (Exception e)
{
return new SendResult(false, e.Message);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
{
return;
}
if (disposing)
{
if (smtpClient != null)
{
smtpClient.Dispose();
smtpClient = null;
}
}
disposed = true;
}
}
public class SendResult : SimpleResult
{
public SendResult(bool success, string message)
: base(success, message)
{
}
public static SendResult Successful
{
get
{
return new SendResult(true, string.Empty);
}
}
}
Usage
var emailFrom = new MailAddress(sender);
var emailTo = new MailAddress(recipient);
var mailMessage = new MailMessage(emailFrom, emailTo)
{
Subject = "Subject ",
Body = "Body"
};
using (var client = new SmtpClientAdapter())
{
return client.Send(mailMessage);
}
Here is a simple way to do it,
public void SendEmail(string address, string subject, string message)
{
string email = "yrshaikh.mail#gmail.com";
string password = "put-your-GMAIL-password-here";
var loginInfo = new NetworkCredential(email, password);
var msg = new MailMessage();
var smtpClient = new SmtpClient("smtp.gmail.com", 587);
msg.From = new MailAddress(email);
msg.To.Add(new MailAddress(address));
msg.Subject = subject;
msg.Body = message;
msg.IsBodyHtml = true;
smtpClient.EnableSsl = true;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = loginInfo;
smtpClient.Send(msg);
}
Source : Link
A operating system API function for this isn't avaiable.

How to send email to multiple address using System.Net.Mail

I have smtp email functionality. it works for single address but has problem in multiple address.
i am passing multiple addresses using following line of code.
MailAddress to = new MailAddress("abc#gmail.com,xyz#gmail.com");
Please let me know the problem as i am not getting any error.
MailMessage msg = new MailMessage();
msg.Body = ....;
msg.To.Add(...);
msg.To.Add(...);
SmtpClient smtp = new SmtpClient();
smtp.Send(msg);
To is a MailAddressCollection, so you can add how many addresses you need.
If you need a display name, try this:
MailAddress to = new MailAddress(
String.Format("{0} <{1}>",display_name, address));
try this..
using System;
using System.Net.Mail;
public class Test
{
public static void Main()
{
SmtpClient client = new SmtpClient("smtphost", 25);
MailMessage msg = new MailMessage("x#y.com", "a#b.com,c#d.com");
msg.Subject = "sdfdsf";
msg.Body = "sdfsdfdsfd";
client.UseDefaultCredentials = true;
client.Send(msg);
}
}
I think you can use this code in order to have List of outgoing Addresses having a display Name (also different):
//1.The ACCOUNT
MailAddress fromAddress = new MailAddress("myaccount#myaccount.com", "my display name");
String fromPassword = "password";
//2.The Destination email Addresses
MailAddressCollection TO_addressList = new MailAddressCollection();
//3.Prepare the Destination email Addresses list
foreach (var curr_address in mailto.Split(new [] {";"}, StringSplitOptions.RemoveEmptyEntries))
{
MailAddress mytoAddress = new MailAddress(curr_address, "Custom display name");
TO_addressList.Add(mytoAddress);
}
//4.The Email Body Message
String body = bodymsg;
//5.Prepare GMAIL SMTP: with SSL on port 587
var smtp = new SmtpClient
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
Credentials = new NetworkCredential(fromAddress.Address, fromPassword),
Timeout = 30000
};
//6.Complete the message and SEND the email:
using (var message = new MailMessage()
{
From = fromAddress,
Subject = subject,
Body = body,
})
{
message.To.Add(TO_addressList.ToString());
smtp.Send(message);
}
StewieFG suggestion is valid but if you want to add the recipient name use this, with what Marco has posted above but is email address first and display name second:
msg.To.Add(new MailAddress("your#email1.com","Your name 1"));
msg.To.Add(new MailAddress("your#email2.com","Your name 2"));
My code to solve this problem:
private void sendMail()
{
//This list can be a parameter of metothd
List<MailAddress> lst = new List<MailAddress>();
lst.Add(new MailAddress("mouse#xxxx.com"));
lst.Add(new MailAddress("duck#xxxx.com"));
lst.Add(new MailAddress("goose#xxxx.com"));
lst.Add(new MailAddress("wolf#xxxx.com"));
try
{
MailMessage objeto_mail = new MailMessage();
SmtpClient client = new SmtpClient();
client.Port = 25;
client.Host = "10.15.130.28"; //or SMTP name
client.Timeout = 10000;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential("from#email.com", "password");
objeto_mail.From = new MailAddress("from#email.com");
//add each email adress
foreach (MailAddress m in lst)
{
objeto_mail.To.Add(m);
}
objeto_mail.Subject = "Sending mail test";
objeto_mail.Body = "Functional test for automatic mail :-)";
client.Send(objeto_mail);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
namespace WebForms.Code.Logging {
public class ObserverLogToEmail: ILog {
private string from;
private string to;
private string subject;
private string body;
private SmtpClient smtpClient;
private MailMessage mailMessage;
private MailPriority mailPriority;
private MailAddressCollection mailAddressCollection;
private MailAddress fromMailAddress, toMailAddress;
public MailAddressCollection toMailAddressCollection {
get;
set;
}
public MailAddressCollection ccMailAddressCollection {
get;
set;
}
public MailAddressCollection bccMailAddressCollection {
get;
set;
}
public ObserverLogToEmail(string from, string to, string subject, string body, SmtpClient smtpClient) {
this.from = from;
this.to = to;
this.subject = subject;
this.body = body;
this.smtpClient = smtpClient;
}
public ObserverLogToEmail(MailAddress fromMailAddress, MailAddress toMailAddress,
string subject, string content, SmtpClient smtpClient) {
try {
this.fromMailAddress = fromMailAddress;
this.toMailAddress = toMailAddress;
this.subject = subject;
this.body = content;
this.smtpClient = smtpClient;
mailAddressCollection = new MailAddressCollection();
} catch {
throw new SmtpException(SmtpStatusCode.CommandNotImplemented);
}
}
public ObserverLogToEmail(MailAddressCollection fromMailAddressCollection,
MailAddressCollection toMailAddressCollection,
string subject, string content, SmtpClient smtpClient) {
try {
this.toMailAddressCollection = toMailAddressCollection;
this.ccMailAddressCollection = ccMailAddressCollection;
this.subject = subject;
this.body = content;
this.smtpClient = smtpClient;
} catch {
throw new SmtpException(SmtpStatusCode.CommandNotImplemented);
}
}
public ObserverLogToEmail(MailAddressCollection toMailAddressCollection,
MailAddressCollection ccMailAddressCollection,
MailAddressCollection bccMailAddressCollection,
string subject, string content, SmtpClient smtpClient) {
try {
this.toMailAddressCollection = toMailAddressCollection;
this.ccMailAddressCollection = ccMailAddressCollection;
this.bccMailAddressCollection = bccMailAddressCollection;
this.subject = subject;
this.body = content;
this.smtpClient = smtpClient;
} catch {
throw new SmtpException(SmtpStatusCode.CommandNotImplemented);
}
}#region ILog Members
// sends a log request via email.
// actual email 'Send' calls are commented out.
// uncomment if you have the proper email privileges.
public void Log(object sender, LogEventArgs e) {
string message = "[" + e.Date.ToString() + "] " + e.SeverityString + ": " + e.Message;
fromMailAddress = new MailAddress("", "HaNN", System.Text.Encoding.UTF8);
toMailAddress = new MailAddress("", "XXX", System.Text.Encoding.UTF8);
mailMessage = new MailMessage(fromMailAddress, toMailAddress);
mailMessage.Subject = subject;
mailMessage.Body = body;
// commented out for now. you need privileges to send email.
// _smtpClient.Send(from, to, subject, body);
smtpClient.Send(mailMessage);
}
public void LogAllEmails(object sender, LogEventArgs e) {
try {
string message = "[" + e.Date.ToString() + "] " + e.SeverityString + ": " + e.Message;
mailMessage = new MailMessage();
mailMessage.Subject = subject;
mailMessage.Body = body;
foreach(MailAddress toMailAddress in toMailAddressCollection) {
mailMessage.To.Add(toMailAddress);
}
foreach(MailAddress ccMailAddress in ccMailAddressCollection) {
mailMessage.CC.Add(ccMailAddress);
}
foreach(MailAddress bccMailAddress in bccMailAddressCollection) {
mailMessage.Bcc.Add(bccMailAddress);
}
if (smtpClient == null) {
var smtp = new SmtpClient {
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
Credentials = new NetworkCredential("yourEmailAddress", "yourPassword"),
Timeout = 30000
};
} else smtpClient.SendAsync(mailMessage, null);
} catch (Exception) {
throw;
}
}
}
I'm used "for" operator.
try
{
string s = textBox2.Text;
string[] f = s.Split(',');
for (int i = 0; i < f.Length; i++)
{
MailMessage message = new MailMessage(); // Create instance of message
message.To.Add(f[i]); // Add receiver
message.From = new System.Net.Mail.MailAddress(c);// Set sender .In this case the same as the username
message.Subject = label3.Text; // Set subject
message.Body = richTextBox1.Text; // Set body of message
client.Send(message); // Send the message
message = null; // Clean up
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
string[] MultiEmails = email.Split(',');
foreach (string ToEmail in MultiEmails)
{
message.To.Add(new MailAddress(ToEmail)); //adding multiple email addresses
}
MailAddress fromAddress = new MailAddress (fromMail,fromName);
MailAddress toAddress = new MailAddress(toMail,toName);
MailMessage message = new MailMessage(fromAddress,toAddress);
message.Subject = subject;
message.Body = body;
SmtpClient smtp = new SmtpClient()
{
Host = host, Port = port,
enabHost = "smtp.gmail.com",
Port = 25,
EnableSsl = true,
UseDefaultCredentials = true,
Credentials = new NetworkCredentials (fromMail, password)
};
smtp.send(message);

Categories