This is the code that I have been making and I just tested to check whether it works but having an error message stating "System.FormatException"
I can't understand what I am having such problem. Please help
public Mail(string sendMail)
{
this.sendAddress = new MailAddress(sendMail); // exception here
}
public void SetToAddress(string toMail)
{
this.toAddress = new MailAddress(toMail);
}
public string SendEmail(string subject, string body)
{
SmtpClient smtp = null;
MailMessage message = null;
try
{
smtp = new SmtpClient
{
Host = "smtp.gmail.com",
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
Credentials = new NetworkCredential(sendAddress.Address, sendPassword),
Timeout = 20000
};
message = new MailMessage(sendAddress, toAddress)
{
Subject = subject,
Body = body
};
smtp.Send(message);
return "send mail ok";
}
catch (Exception e)
{
return "send mail fail";
}
finally
{
if (smtp != null) { smtp.Dispose(); }
if (message != null) { message.Dispose(); }
}
}
}
namespace WindowsFormsApp12
{
public partial class Form1 : Form
{
Mail mail = new Mail("email address type");
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string toAddress = this.textBox2.Text;
string subject = this.textBox1.Text;
string body = this.textBox3.Text;
if (toAddress == "")
{
MessageBox.Show("type in email address");
}
if (subject == "")
{
MessageBox.Show("type in email title");
}
if (body == "")
{
MessageBox.Show("type in email contents");
}
mail.SetToAddress(toAddress);
MessageBox.Show(mail.SendEmail(subject, body));
}
}
}
You are not setting the .from part of mail.
mail = new MailMessage(sendAddress, toAddress)
{
Subject = subject,
Body = body,
From = new MailAddress("Blah#Blah.com;")
};
to addresses can be added like
mail.To.Add("email#address.com");
FormatException for the constructor of MailAddress indicates an invalid email address. Source MSDN documentation for MailAddress constructor.
Related
I am trying to attach a file in the AWS ses email. The file is being received by HttpPostedFileBase but the problem is I have no idea how can I use it to attach in a method called GetMessageBody() because body.Attachments.Add() only takes input for file location, not the HttpPostedFileBase file. Any idea how can I attach the file received by HttpPostedFileBase?
Use case:
[HttpPost, ValidateInput(false)]
public ActionResult SendHtmlEmailWithAttachment(HttpPostedFileBase file)
{
AWSEmailWithAttachment.SendAttachmentEmails("test#gmail.com", "noreply#test.co.uk", "my subject", file);
return Json("ok");
}
AWS ses email class:
public class AWSEmailWithAttachment
{
private static BodyBuilder GetMessageBody(HttpPostedFileBase attachment)
{
var body = new BodyBuilder()
{
HtmlBody = #"<p>Amazon SES Test body</p>",
TextBody = "Amazon SES Test body",
};
body.Attachments.Add(#"C:\Users\liaka\OneDrive\Desktop\attachment.txt");//I can use file location to attach with email but no idea how can i take file input form HttpPostedFileBase
return body;
}
private static MimeMessage GetMessage(string receiveraddress, string senderaddress, string subject, HttpPostedFileBase attachment)
{
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Foo Bar", senderaddress));
message.To.Add(new MailboxAddress(string.Empty, receiveraddress));
message.Subject = subject;
message.Body = GetMessageBody(attachment).ToMessageBody();
return message;
}
private static MemoryStream GetMessageStream(string receiveraddress, string senderaddress, string subject, HttpPostedFileBase attachment)
{
var stream = new MemoryStream();
GetMessage(receiveraddress, senderaddress, subject, attachment).WriteTo(stream);
return stream;
}
public static void SendAttachmentEmails(string receiveraddress, string senderaddress, string subject, HttpPostedFileBase attachment)
{
var credentals = new BasicAWSCredentials(Credentials.AWS_Access_Key_ID, Credentials.AWS_Secret_Access_Key);
using (var client = new AmazonSimpleEmailServiceClient(credentals, RegionEndpoint.EUWest2))
{
var sendRequest = new SendRawEmailRequest { RawMessage = new RawMessage(GetMessageStream(receiveraddress, senderaddress, subject, attachment)) };
try
{
var response = client.SendRawEmail(sendRequest);
}
catch (Exception e) { }
}
}
}
I've successfully created custom email service provider for UserManager by extending IIdentityMessageService:
public class ExchangeEmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
using (var client = new SmtpClient())
{
client.Host = "mail.example.com";
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(#"noreply", "P#ssw0rd");
var from = new MailAddress("no-reply#example.com");
var to = new MailAddress(message.Destination);
var mailMessage = new MailMessage(from, to)
{
Subject = message.Subject,
Body = message.Body,
IsBodyHtml = true
};
await client.SendMailAsync(mailMessage);
}
}
}
Inside UserManager's Create I'm creating new instance of my service and assigning it to EmailService:
userManager.EmailService = new ExchangeEmailService();
This all works fine, but I have requirement to send emails from different email addresses, based on place this is called from, unfortunately UserManager.SendEmailAsync isn't allowing me to pass anything except userId, subject and body.
Ideally I'd like to be able to specify email address when calling SendEmailAcync or enum value.
I've searched in UserManager source and I thought about creating custom SendEmailAsync implementation, but I'd have to change multiple places - IIdentityMessageService, UserManager.
I know I can create new interface and build my email sending class on it, but I'd like to keep changes to minimum.
What I'd like to get:
I'd like to have enum containing names of mailboxes:
public enum Mailboxes
{
Noreply = 0,
Service = 1,
Contact = 2
}
and be able to call SendEmailAsync with that additional parameter:
await UserManager.SendEmailAsync(user.Id, "Account created", "Nice email content.", Mailboxes.Noreply );
I'm aware that I can set different title and use same email address, but this is requirement I got.
How can I do that?
A hack would be to create a model to store what you want sent to the service
public class MessageBody {
public string Body { get; set; }
public MailBoxes Source { get; set; }
}
and then serialize it (JSON maybe) as the body parameter of the SendEmailAsync method call.
var message = new MessageBody {
Body = "Nice email content.",
Source = Mailboxes.Noreply
};
var body = JsonConvert.SerializeObject(message);
await UserManager.SendEmailAsync(user.Id, "Account created", body);
The service would then deserialize the model, construct the email with the custom info and then send the email.
public class ExchangeEmailService : IIdentityMessageService {
readonly IMailBoxProvider provider;
public ExchangeEmailService(IMailBoxProvider provider) {
this.provider = provider;
}
public async Task SendAsync(IdentityMessage message) {
using (var client = new SmtpClient()) {
client.Host = "mail.example.com";
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(#"noreply", "P#ssw0rd");
//Get the body and from address
var fromEmailAddress = "default-email#example.com";
var body = message.Body;
try {
var msg = JsonConvert.DeserializeObject<MessageBody>(body);
if(msg != null) {
body = msg.Body;
fromEmailAddress = provider.GetMailbox(msg.Source);
}
} catch { }
var from = new MailAddress(fromEmailAddress);
var to = new MailAddress(message.Destination);
var mailMessage = new MailMessage(from, to)
{
Subject = message.Subject,
Body = body,
IsBodyHtml = true
};
await client.SendMailAsync(mailMessage);
}
}
}
And just make sure to assigning it to UserManager.EmailService:
userManager.EmailService = new ExchangeEmailService(new MailBoxProvider());
I am using smtp with gmail (already setup in my gmail account to allow it). But everytime that a different computer try to do it, gmail says that someone tryed to use my account and ask if it was me (so my confirmation e-mail isn't sended).
using Microsoft.AspNet.Identity;
using System;
using System.Configuration;
using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;
namespace Prac.Services
{
public class EMail : IIdentityMessageService
{
#region Private Fields
private static string FromAddress;
private static string strSmtpClient;
private static string UserID;
private static string Password;
private static string SMTPPort;
private static bool bEnableSSL;
#endregion
#region Interface Implementation
public async Task SendAsync(IdentityMessage message)
{
await configSendGridasync(message);
}
#endregion
#region Send Email Method
public async Task configSendGridasync(IdentityMessage message)
{
GetMailData();
dynamic MailMessage = new MailMessage();
MailMessage.From = new MailAddress(FromAddress);
MailMessage.To.Add(message.Destination);
MailMessage.Subject = message.Subject;
MailMessage.IsBodyHtml = true;
MailMessage.Body = message.Body;
SmtpClient SmtpClient = new SmtpClient();
SmtpClient.Host = strSmtpClient;
SmtpClient.EnableSsl = bEnableSSL;
SmtpClient.Port = Int32.Parse(SMTPPort);
SmtpClient.Credentials = new NetworkCredential(UserID, Password);
try
{
try
{
SmtpClient.Send(MailMessage);
}
catch (Exception ex)
{
}
}
catch (SmtpFailedRecipientsException ex)
{
for (int i = 0; i <= ex.InnerExceptions.Length; i++)
{
SmtpStatusCode status = ex.StatusCode;
if ((status == SmtpStatusCode.MailboxBusy) | (status == SmtpStatusCode.MailboxUnavailable))
{
System.Threading.Thread.Sleep(5000);
SmtpClient.Send(MailMessage);
}
}
}
}
#endregion
#region Get Email provider data From Web.config file
private static void GetMailData()
{
FromAddress = ConfigurationManager.AppSettings.Get("FromAddress");
strSmtpClient = ConfigurationManager.AppSettings.Get("SmtpClient");
UserID = ConfigurationManager.AppSettings.Get("UserID");
Password = ConfigurationManager.AppSettings.Get("Password");
//ReplyTo = System.Configuration.ConfigurationManager.AppSettings.Get("ReplyTo");
SMTPPort = ConfigurationManager.AppSettings.Get("SMTPPort");
if ((ConfigurationManager.AppSettings.Get("EnableSSL") == null))
{
}
else
{
if ((System.Configuration.ConfigurationManager.AppSettings.Get("EnableSSL").ToUpper() == "YES"))
{
bEnableSSL = true;
}
else
{
bEnableSSL = false;
}
}
}
#endregion
}
}
GMAIL defaults to not allowing smtp access
Once you login to your Gmail account, type this into the URL bar:
https://myaccount.google.com/u/1/security?hl=en#connectedapps
At the bottom you'll see a setting "Allow less secure apps" Toggle
that to "ON"
I try send mail with my smtp client but i dont have exception and mail doesn't recieved.
public void SendSMTPMail(string from, string to, string subject, string body)
{
var smtp_client = new SmtpClient("mail.mydomain.gr",25);
smtp_client.UseDefaultCredentials = false;
smtp_client.EnableSsl = false;
smtp_client.Credentials = new NetworkCredential("noreply#mydomain.gr", "mypass");
ServicePointManager.ServerCertificateValidationCallback = (s, certificate, chain, sslPolicyErrors) => true;
var msg = new MailMessage(from, to );
msg.Subject = subject;
msg.Body = body;
smtp_client.SendAsync(msg , string.Empty);
}
i use breakpoint and i find some info
smtp_client.ServicePoint System.NotImplementException: The request feature is not implemented
but i use this code with another smtp and works fine. Any help ?
As an alternative, you could use my MailKit library to send mail using Xamarin.iOS/Android/Mac.
public void SendSMTPMail(string from, string to, string subject, string body)
{
var message = new MimeMessage ();
var builder = new BodyBuilder ();
message.From.Add (InternetAddress.Parse (from));
message.To.Add (InternetAddress.Parse (to));
message.Subject = subject;
builder.TextBody = body;
message.Body = builder.ToMessageBody ();
using (var client = new SmtpClient ()) {
client.ServerCertificateValidationCallback = (s, certificate, chain, sslPolicyErrors) => true;
client.Connect ("mail.mydomain.gr", 25, false);
client.Authenticate ("noreply#mydomain.gr", "mypass");
client.Send (message);
client.Disconnect (true);
}
}
It seems like you can't use the System.Net.Mail.SmtpClient in Xamarin.
Instead you should use the the mail service with native implementation. Tiny example here. The Forms code:
public abstract class EmailService
{
public static readonly Lazy<EmailService> Instance = new Lazy<EmailService>(() => DependencyService.Get<EmailService>());
public abstract bool CanSend { get; }
public abstract void ShowDraft(string subject, string body, bool html, string to, byte[] screenshot = null);
public abstract void ShowDraft(string subject, string body, bool html, string[] to, string[] cc, string[] bcc, byte[] screenshot = null);
}
The native iOS code:
public class EmailServiceIos : EmailService
{
public override bool CanSend
{
get
{
return MFMailComposeViewController.CanSendMail;
}
}
public override void ShowDraft(
string subject,
string body,
bool html,
string[] to,
string[] cc,
string[] bcc,
byte[] screenshot = null)
{
var mailer = new MFMailComposeViewController();
mailer.SetMessageBody(body ?? string.Empty, html);
mailer.SetSubject(subject ?? string.Empty);
mailer.SetCcRecipients(cc);
mailer.SetToRecipients(to);
mailer.Finished += (s, e) => ((MFMailComposeViewController)s).DismissViewController(true, () => { });
if (screenshot != null)
{
mailer.AddAttachmentData(NSData.FromArray(screenshot), "image/png", "screenshot.png");
}
UIViewController vc = UIApplication.SharedApplication.KeyWindow.RootViewController;
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
vc.PresentViewController(mailer, true, null);
}
public override void ShowDraft(string subject, string body, bool html, string to, byte[] screenshot = null)
{
this.ShowDraft(subject, body, html, new[] { to }, new string[] { }, new string[] { }, screenshot);
}
}
And invoke the whole thing from the Forms code like:
var emailService = DependencyService.Get<EmailService>();
if (emailService.CanSend)
{
emailService.ShowDraft(
"Your caption",
"Your text",
true,
"your#ddress.com");
}
We have some (synchronous) email code, which creates a class that creates an SmtpClient, and then sends an email. The SmtpClient is not reused; however we get the following exception every now and then:
System.Web.HttpUnhandledException (0x80004005): Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.InvalidOperationException: An asynchronous call is already in progress. It must be completed or canceled before you can call this method.
at System.Net.Mail.SmtpClient.Send(MailMessage message)
at EmailSender.SendMail(MailAddress fromMailAddress, string to, String subject, String body, Boolean highPriority) in ...\EmailSender.cs:line 143
Code looks like this:
// ...
var emailSender = new EmailSender();
emailSender.SendMail(toEmail, subject, body, true);
// emailSender not used past this point
// ...
public class EmailSender : IEmailSender
{
private readonly SmtpClient smtp;
public EmailSender()
{
smtp = new SmtpClient();
}
public void SendMail(MailAddress fromMailAddress, string to, string subject, string body, bool highPriority)
{
if (fromMailAddress == null)
throw new Exception();
if (to == null)
throw new ArgumentException("No valid recipients were supplied.", "to");
// Mail initialization
var mailMsg = new MailMessage
{
From = fromMailAddress,
Subject = subject,
Body = body,
IsBodyHtml = true,
Priority = (highPriority) ? MailPriority.High : MailPriority.Normal
};
mailMsg.To.Add(to);
smtp.Send(mailMsg);
}
}
You need to dispose of the SmtpClient using Dispose, using or by implementing the disposable pattern for your class EmailSender (which more appropriate here because you are tying the lifetime of the SmtpClient to the lifetime of the EmailSender in the constructor.)
That might solve this exception.
My guess is that the SmtpClient was not designed to send multiple messages concurrently.
I would change the class like this instead:
public class EmailSender : IEmailSender
{
Queue<MailMessage> _messages = new Queue<MailMessage>();
SmtpClient _client = new SmtpClient();
public EmailSender()
{
}
public void SendMail(MailAddress fromMailAddress, string to, string subject, string body, bool highPriority)
{
if (fromMailAddress == null)
throw new ArgumentNullException("fromMailAddress");
if (to == null)
throw new ArgumentException("No valid recipients were supplied.", "to");
// Mail initialization
var mailMsg = new MailMessage
{
From = fromMailAddress,
Subject = subject,
Body = body,
IsBodyHtml = true,
Priority = (highPriority) ? MailPriority.High : MailPriority.Normal
};
mailMsg.To.Add(to);
lock (_messages)
{
_messages.Enqueue(mailMsg);
if (_messages.Count == 1)
{
ThreadPool.QueueUserWorkItem(SendEmailInternal);
}
}
}
protected virtual void SendEmailInternal(object state)
{
while (true)
{
MailMessage msg;
lock (_messages)
{
if (_messages.Count == 0)
return;
msg = _messages.Dequeue();
}
_client.Send(msg)
}
}
}
As there are really no reason to create the client in the constructor.
I also changed so that the class throws ArgumentNullException and not Exception if fromMailAddress is null. An empty Exception doesn't say much..
Update
The code do now use a thread pool thread for the sending (and reusing the smtpclient).