Send mail from my SMTP Client in xamarin - c#

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");
}

Related

How to attach HttpPostedFileBase file in aws ses email in C#

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) { }
}
}
}

Getting failures for C# email sending

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.

ASP.NET Identity UserManager IIdentityMessageService pass extra parameters to SendAsync

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());

Trying to use SMTP with gmail

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"

Asp.Net - Identity 2 - Attach files in emails fired by EmailService

I´m using Asp.Net-Identity-2 to manage user access in my app.
I´m using EmailService (UserManager.SendEmail) to send confirmation email messages and I´d like to send a formatted HTML message, and I want attach images in it.
How can I do that??
Setup Identity User Manager EmailService
public class AppUserManager : UserManager<AppUser>
{
public AppUserManager(IUserStore<AppUser> store) : base(store) { }
public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
{
AppUserManager manager = new AppUserManager(new UserStore<AppUser>(db));
//Some setup code here ....
//Hook to my EmailService (see class MyEmailService.cs)
manager.EmailService = new MyEmailService();
return manager;
} //Create
} //class
MyEmailService
public class MyEmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
MailMessage email = new MailMessage("me#sample.com", message.Destination);
email.Subject = message.Subject;
email.Body = message.Body;
email.IsBodyHtml = true;
var mailClient = new SmtpClient();
mailClient.Host = "EmailServer";
mailClient.Port = 25;
return mailClient.SendMailAsync(email);
} //SendAsync
} //class
Action to send email
public ActionResult ForgotPassword(string email)
{
if (ModelState.IsValid)
{
AppUser user = UserManager.FindByEmail(email);
if (user == null || !(UserManager.IsEmailConfirmed(user.Id)))
{
return View("../Home/Index");
} //if
string code = UserManager.GenerateEmailConfirmationToken(user.Id);
string callbackUrl = Url.Action("ResetPassword", "Admin", new { Id = user.Id, code = code }, protocol: Request.Url.Scheme);
string strMessage = getHTMLMessage(); //variable Html message here, with images references in it (ex. "<img src='cid:IMAGE_TITLE'>")
UserManager.SendEmail(user.Id, "Message Subject", strMessage);
return View("../Home/Index");
}
// If we got this far, something failed, redisplay form
return View();
} //ForgotPassword
My doubt is how to attach images in that message...
Thanks for any help..
Julio Schurt
I had to create another method in my service and call it directly
public Task SendAsync(IdentityMessage message, IEnumerable<KeyValuePair<string, Stream>> attach)
{
var myMessage = new SendGridMessage() { From = new MailAddress("my#email.com") };
myMessage.AddTo(message.Destination);
myMessage.Subject = message.Subject;
myMessage.Html = message.Body;
myMessage.Text = message.Body;
var credentials = new NetworkCredential("myuser", "mypassword");
var transportWeb = new Web(credentials);
foreach (var file in attach)
{
myMessage.AddAttachment(file.Value,file.Key);
}
return transportWeb.DeliverAsync(myMessage);
}
EDIT: (2015-08-14)
Final class:
public class EmailService : IIdentityMessageService
{
const string from = "mail#domain.com";
const string username = "username";//Environment.GetEnvironmentVariable("SENDGRID_USER");
const string pswd = "password";//Environment.GetEnvironmentVariable("SENDGRID_PASS");
private List<KeyValuePair<string, Stream>> _attachments;
private List<KeyValuePair<string, string>> _recipients;
public Task SendAsync(IdentityMessage message)
{
var myMessage = new SendGridMessage() { From = new MailAddress(from) };
var credentials = new NetworkCredential(username, pswd);
var transportWeb = new Web(credentials);
myMessage.AddTo(message.Destination);
if (_recipients != null)
{
_recipients.ForEach(r => myMessage.AddTo(string.Format("{0} {1}", r.Key, r.Value)));
}
myMessage.Subject = message.Subject;
myMessage.Html = message.Body;
myMessage.Text = message.Body;
if (_attachments != null)
{
foreach (var attachment in _attachments)
{
myMessage.AddAttachment(attachment.Value, attachment.Key);
}
}
return transportWeb.DeliverAsync(myMessage);
}
public Task SendAsync(IdentityMessage message, IEnumerable<KeyValuePair<string, Stream>> attachments)
{
var myMessage = new SendGridMessage() { From = new MailAddress(from) };
var credentials = new NetworkCredential(username, pswd);
var transportWeb = new Web(credentials);
myMessage.AddTo(message.Destination);
myMessage.Subject = message.Subject;
myMessage.Html = message.Body;
myMessage.Text = message.Body;
foreach (var attachment in attachments)
{
myMessage.AddAttachment(attachment.Value, attachment.Key);
}
return transportWeb.DeliverAsync(myMessage);
}
public Task SendAsync(IdentityMessage message, KeyValuePair<string, Stream> attachment)
{
var myMessage = new SendGridMessage() { From = new MailAddress(from) };
var credentials = new NetworkCredential(username, pswd);
var transportWeb = new Web(credentials);
myMessage.AddTo(message.Destination);
myMessage.Subject = message.Subject;
myMessage.Html = message.Body;
myMessage.Text = message.Body;
myMessage.AddAttachment(attachment.Value, attachment.Key);
return transportWeb.DeliverAsync(myMessage);
}
public void AddTo(string name,string mail)
{
_recipients = _recipients ?? new List<KeyValuePair<string, string>>();
_recipients.Add(new KeyValuePair<string, string>(name, string.Format("<{0}>", mail)));
}
public void AddAttachment(string name, Stream file)
{
_attachments = _attachments ?? new List<KeyValuePair<string, Stream>>();
_attachments.Add(new KeyValuePair<string, Stream>(name, file));
}
public void AddAttachment<T>(string name, T records)
{
var jsonSerialiser = new JavaScriptSerializer();
var json = jsonSerialiser.Serialize(records);
var bytes = Encoding.UTF8.GetBytes(json);
var ms = new MemoryStream(bytes);
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
_attachments = _attachments ?? new List<KeyValuePair<string, Stream>>();
_attachments.Add(new KeyValuePair<string, Stream>(name, ms));
}
}
Then can use it...
// use it directly
var emailService = new EmailService();
IdentityMessage msg = new IdentityMessage()
{
Destination = "test <test#domain.com>",
Subject = "Subject",
Body = "Body"
};
emailService.AddTo("Name1", "mail1#domain.com");
emailService.AddTo("Name2", "mail2#domain.com");
emailService.AddTo("Name3", "mail3#domaincom");
emailService.AddAttachment(filename", stream);
await emailService.SendAsync(msg);
// Or use it from UserManager
(UserManager.EmailService as EmailService).AddAttachment("name", yourStream);
await UserManager.SendEmailAsync("userid", "subject", "body");

Categories