I host my web app which is written in .net mvc2 on amazon ec2. currrently use gmail smtp to send email. beacuse of google for startup email quota cant send more than 500 email a day. So decide to move amazon ses. How can use amazon ses with asp.net mvc2? How about configuration etc? Is email will send via gmail? because our email provider is gmail. etc.
Send Email via Amazon is a right decision. Because when you move to amazon you will immediately get 2000 email free per day which is greater than googla apps 500 emails quota a day.
Step by Step:
Go to http://aws.amazon.com/ses
and click Sign Up for Amazon SES.
To get your AWS access identifiers
verify your email address - email
which you will send email via. You
need perl packages installled on
your computer to test email
features.
include:amazonses.com to your dns record.
Step by step documentation.
http://docs.aws.amazon.com/ses/latest/DeveloperGuide/getting-started.html
There is a Amazon SES (Simple Email Service) C# Wrapper on codeplex you can use this wrapper to send emails.
Amazon SES C# Wrapper
Easiest way is to download the SDK via Nuget (package is called AWSSDK) or download the SDK from Amazon's site. The sdk download from their site has an example project that shows you how to call their API to send email. The only configuration is plugging in your api keys. The trickiest part is verifying your send address (and any test receipients) but their is an API call there too to send the test message. You will then need to log in and verify those email addresses. The email will be sent through Amazon (that is the whole point) but the from email address can be your gmail address.
#gandil I created this very simple code to send emails
using Amazon;
using Amazon.SimpleEmail;
using Amazon.SimpleEmail.Model;
using System.IO;
namespace SendEmail
{
class Program
{
static void Main(string[] args)
{
//Remember to enter your (AWSAccessKeyID, AWSSecretAccessKey) if not using and IAM User with credentials assigned to your instance and your RegionEndpoint
using (var client = new AmazonSimpleEmailServiceClient("YourAWSAccessKeyID", "YourAWSSecretAccessKey", RegionEndpoint.USEast1))
{
var emailRequest = new SendEmailRequest()
{
Source = "FROMADDRESS#TEST.COM",
Destination = new Destination(),
Message = new Message()
};
emailRequest.Destination.ToAddresses.Add("TOADDRESS#TEST.COM");
emailRequest.Message.Subject = new Content("Hello World");
emailRequest.Message.Body = new Body(new Content("Hello World"));
client.SendEmail(emailRequest);
}
}
}
}
You can find the code in here https://github.com/gianluis90/amazon-send-email
Download AWSSDK.dll file from internet
use following name-spaces
using Amazon;
using Amazon.SimpleEmail;
using Amazon.SimpleEmail.Model;
using System.Net.Mail;
2 . Add to web config...
<appSettings>
<add key="AWSAccessKey" value="Your AWS Access Key" />
<add key="AWSSecretKey" value="Your AWS secret Key" />
</appSettings>
3 . Add a AWSEmailSevice class to your project that will allow to send mail via AWS ses...
public class AWSEmailSevice
{
//create smtp client instance...
SmtpClient smtpClient = new SmtpClient();
//for sent mail notification...
bool _isMailSent = false;
//Attached file path...
public string AttachedFile = string.Empty;
//HTML Template used in mail ...
public string Template = string.Empty;
//hold the final template data list of users...
public string _finalTemplate = string.Empty;
//Template replacements varibales dictionary....
public Dictionary<string, string> Replacements = new Dictionary<string, string>();
public bool SendMail(MailMessage mailMessage)
{
try
{
if (mailMessage != null)
{
//code for fixed things
//from address...
mailMessage.From = new MailAddress("from#gmail.com");
//set priority high
mailMessage.Priority = System.Net.Mail.MailPriority.High;
//Allow html true..
mailMessage.IsBodyHtml = true;
//Set attachment data..
if (!string.IsNullOrEmpty(AttachedFile))
{
//clear old attachment..
mailMessage.Attachments.Clear();
Attachment atchFile = new Attachment(AttachedFile);
mailMessage.Attachments.Add(atchFile);
}
//Read email template data ...
if (!string.IsNullOrEmpty(Template))
_finalTemplate = File.ReadAllText(Template);
//check replacements ...
if (Replacements.Count > 0)
{
//exception attached template..
if (string.IsNullOrEmpty(_finalTemplate))
{
throw new Exception("Set Template field (i.e. file path) while using replacement field");
}
foreach (var item in Replacements)
{
//Replace Required Variables...
_finalTemplate = _finalTemplate.Replace("<%" + item.Key.ToString() + "%>", item.Value.ToString());
}
}
//Set template...
mailMessage.Body = _finalTemplate;
//Send Email Using AWS SES...
var message = mailMessage;
var stream = FromMailMessageToMemoryStream(message);
using (AmazonSimpleEmailServiceClient client = new AmazonSimpleEmailServiceClient(
ConfigurationManager.AppSettings["AWSAccessKey"].ToString(),
ConfigurationManager.AppSettings["AWSSecretKey"].ToString(),
RegionEndpoint.USWest2))
{
var sendRequest = new SendRawEmailRequest { RawMessage = new RawMessage { Data = stream } };
var response = client.SendRawEmail(sendRequest);
//return true ...
_isMailSent = true;
}
}
else
{
_isMailSent = false;
}
}
catch (Exception ex)
{
throw ex;
}
return _isMailSent;
}
private MemoryStream FromMailMessageToMemoryStream(MailMessage message)
{
Assembly assembly = typeof(SmtpClient).Assembly;
Type mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
MemoryStream stream = new MemoryStream();
ConstructorInfo mailWriterContructor =
mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);
object mailWriter = mailWriterContructor.Invoke(new object[] { stream });
MethodInfo sendMethod =
typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
if (sendMethod.GetParameters().Length == 3)
{
sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { mailWriter, true, true }, null); // .NET 4.x
}
else
{
sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { mailWriter, true }, null); // .NET < 4.0
}
MethodInfo closeMethod =
mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);
return stream;
}
}
Use above class to send mail anyone with attachment and template varibales replacement (it's optional)
// Call this method to send your email
public string SendEmailViaAWS()
{
string emailStatus = "";
//Create instance for send email...
AWSEmailSevice emailContaint = new AWSEmailSevice();
MailMessage emailStuff = new MailMessage();
//email subject..
emailStuff.Subject = "Your Email subject";
//region Optional email stuff
//Templates to be used in email / Add your Html template path ..
emailContaint.Template = #"\Templates\MyUserNotification.html";
//add file attachment / add your file ...
emailContaint.AttachedFile = "\ExcelReport\report.pdf";
//Note :In case of template
//if youe want to replace variables in run time
//just add replacements like <%FirstName%> , <%OrderNo%> , in HTML Template
//if you are using some varibales in template then add
// Hold first name..
var FirstName = "User First Name";
// Hold email..
var OrderNo = 1236;
//firstname replacement..
emailContaint.Replacements.Add("FirstName", FirstName.ToString());
emailContaint.Replacements.Add("OrderNo", OrderNo.ToString());
// endregion option email stuff
//user OrderNo replacement...
emailContaint.To.Add(new MailAddress("TOEmail#gmail.com"));
//mail sent status
bool isSent = emailContaint.SendMail(emailStuff);
if(isSent)
{
emailStatus = "Success";
}
else
{
emailStatus = "Fail";
}
return emailStatus ; }
Following is how I sent email with attachment
public static void SendMailSynch(string file1, string sentFrom, List<string> recipientsList, string subject, string body)
{
string smtpClient = "email-smtp.us-east-1.amazonaws.com"; //Correct it
string conSMTPUsername = "<USERNAME>";
string conSMTPPassword = "<PWD>";
string username = conSMTPUsername;
string password = conSMTPPassword;
// Configure the client:
System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient(smtpClient);
client.Port = 25;
client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential(username, password);
client.EnableSsl = true;
client.Credentials = credentials;
// Create the message:
var mail = new System.Net.Mail.MailMessage();
mail.From = new MailAddress(sentFrom);
foreach (string recipient in recipientsList)
{
mail.To.Add(recipient);
}
mail.Bcc.Add("test#test.com");
mail.Subject = subject;
mail.Body = body;
mail.IsBodyHtml = true;
Attachment attachment1 = new Attachment(file1, MediaTypeNames.Application.Octet);
ContentDisposition disposition = attachment1.ContentDisposition;
disposition.CreationDate = System.IO.File.GetCreationTime(file1);
disposition.ModificationDate = System.IO.File.GetLastWriteTime(file1);
disposition.ReadDate = System.IO.File.GetLastAccessTime(file1);
mail.Attachments.Add(attachment1);
client.Send(mail);
}
Related
further to this question, i have the same problem. PubFolder on Prem , users in O365
I have fetched and added the routing headers from Glen's post but still get the error
GetToken works...
https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
GetX headers works...
https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/public-folder-access-with-ews-in-exchange
--->> ewsClient.FindFolders(WellKnownFolderName.PublicFoldersRoot, new FolderView(10))
Microsoft.Exchange.WebServices.Data.ServiceResponseException: 'There are no public folder servers available.'
static async System.Threading.Tasks.Task Test3()
{
string ClientId = ConfigurationManager.AppSettings["appId"];
string TenantId = ConfigurationManager.AppSettings["tenantId"];
string secret = ConfigurationManager.AppSettings["clientSecret"];
string uMbox = ConfigurationManager.AppSettings["userId"];
string uPwd = ConfigurationManager.AppSettings["userPWD"];
// Using Microsoft.Identity.Client 4.22.0
//https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth//
var cca = ConfidentialClientApplicationBuilder
.Create(ClientId)
.WithClientSecret(secret)
.WithTenantId(TenantId)
.Build();
var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
try
{
var authResult = await cca.AcquireTokenForClient(ewsScopes)
.ExecuteAsync();
// Configure the ExchangeService with the access token
var ewsClient = new ExchangeService();
ewsClient.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
ewsClient.Credentials = new OAuthCredentials(authResult.AccessToken);
ewsClient.ImpersonatedUserId =
new ImpersonatedUserId(ConnectingIdType.SmtpAddress, uMbox);
AutodiscoverService autodiscoverService = GetAutodiscoverService(uMbox, uPwd);
GetUserSettingsResponse userResponse = GetUserSettings(autodiscoverService, uMbox, 3, UserSettingName.PublicFolderInformation, UserSettingName.InternalRpcClientServer);
string pfAnchorHeader= userResponse.Settings[UserSettingName.PublicFolderInformation].ToString();
string pfMailboxHeader = userResponse.Settings[UserSettingName.InternalRpcClientServer].ToString(); ;
// Make an EWS call
var folders = ewsClient.FindFolders(WellKnownFolderName.MsgFolderRoot, new FolderView(10));
foreach (var folder in folders)
{
Console.WriteLine($"Folder: {folder.DisplayName}");
}
//get Public folder root
//Include x-anchormailbox header
Console.WriteLine("X-AnchorMailbox value for public folder hierarchy requests: {0}", pfAnchorHeader);
Console.WriteLine("X-PublicFolderMailbox value for public folder hierarchy requests: {0}", pfMailboxHeader);
//var test3 = GetMailboxGuidAddress(ewsClient, pfAnchorHeader, pfMailboxHeader, uMbox);
///https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-route-public-folder-content-requests <summary>
ewsClient.HttpHeaders.Add("X-AnchorMailbox", userResponse.Settings[UserSettingName.PublicFolderInformation].ToString());
//ewsClient.HttpHeaders.Add("X-AnchorMailbox", "SharedPublicFolder#contoso.com");
ewsClient.HttpHeaders.Add("X-PublicFolderMailbox", userResponse.Settings[UserSettingName.InternalRpcClientServer].ToString());
try
{
var pubfolders = ewsClient.FindFolders(WellKnownFolderName.PublicFoldersRoot, new FolderView(10));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
foreach (var folder in folders)
{
Console.WriteLine($"Folder: {folder.DisplayName}");
}
}
catch (MsalException ex)
{
Console.WriteLine($"Error acquiring access token: {ex}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex}");
}
if (System.Diagnostics.Debugger.IsAttached)
{
Console.WriteLine("Hit any key to exit...");
Console.ReadKey();
}
}
public static AutodiscoverService GetAutodiscoverService(string username, string pwd)
{
AutodiscoverService adAutoDiscoverService = new AutodiscoverService();
adAutoDiscoverService.Credentials = new WebCredentials(username, pwd);
adAutoDiscoverService.EnableScpLookup = true;
adAutoDiscoverService.RedirectionUrlValidationCallback = RedirectionUrlValidationCallback;
adAutoDiscoverService.PreAuthenticate = true;
adAutoDiscoverService.TraceEnabled = true;
adAutoDiscoverService.KeepAlive = false;
return adAutoDiscoverService;
}
public static GetUserSettingsResponse GetUserSettings(
AutodiscoverService service,
string emailAddress,
int maxHops,
params UserSettingName[] settings)
{
Uri url = null;
GetUserSettingsResponse response = null;
for (int attempt = 0; attempt < maxHops; attempt++)
{
service.Url = url;
service.EnableScpLookup = (attempt < 2);
response = service.GetUserSettings(emailAddress, settings);
if (response.ErrorCode == AutodiscoverErrorCode.RedirectAddress)
{
url = new Uri(response.RedirectTarget);
}
else if (response.ErrorCode == AutodiscoverErrorCode.RedirectUrl)
{
url = new Uri(response.RedirectTarget);
}
else
{
return response;
}
}
throw new Exception("No suitable Autodiscover endpoint was found.");
}
Your code won't work against an OnPrem Public folder tree as EWS in Office365 won't proxy to an OnPrem Exchange Org (even if hybrid is setup). (Outlook MAPI is a little different and allows this via versa setup but in that case it never proxies either it just makes a different connection to that store and its all the Outlook client doing this).
Because your trying to use the client credentials oauth flow for that to work onPrem you must have setup hybrid modern authentication https://learn.microsoft.com/en-us/microsoft-365/enterprise/hybrid-modern-auth-overview?view=o365-worldwide. Then you need to acquire a token with an audience set to the local OnPrem endpoint. (this is usually just your onPrem ews endpoint's host name but it should be one of the service principal names configured in your hybrid auth setup Get-MsolServicePrincipal). So in your code you would change
var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
to
var ewsScopes = new string[] { "https://OnPrem.whatever.com/.default" };
which will then give you a token with an audience set for the onprem server then you need to send the EWS request to that endpoint so change that eg
ewsClient.Url = new Uri("https://OnPrem.whatever.com/EWS/Exchange.asmx");
if Hybird Modern Auth is setup then you need to default back to use Integrated or Basic Authenticaiton.
After reading this I've been trying to create an installation in my xamarin.android app but I keep getting an 'Unauthorized error' I feel that I'm missing something. Any help is appreciated.
Previously I was able to register with the hub using
var regID = hub.Register(token, tags.ToArray()).RegistrationId;
so I'm sure my hub has been setup correctly and that I am using the correct connectionstring.
My installation object
install.installationId = installationId; //guid
install.tags = Tags;
install.platform = "gcm";
install.pushChannel = token; //refresh token from fcm
Call to Create installation
private async Task<HttpStatusCode> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation,
string hubName, string listenConnectionString)
{
if (deviceInstallation.installationId == null)
return HttpStatusCode.BadRequest;
// Parse connection string (https://msdn.microsoft.com/library/azure/dn495627.aspx)
ConnectionStringUtility connectionSaSUtil = new ConnectionStringUtility(listenConnectionString);
string hubResource = "installations/" + deviceInstallation.installationId + "?";
string apiVersion = "api-version=2015-04";
// Determine the targetUri that we will sign
string uri = connectionSaSUtil.Endpoint + hubName + "/" + hubResource + apiVersion;
//=== Generate SaS Security Token for Authorization header ===
// See, https://msdn.microsoft.com/library/azure/dn495627.aspx
string SasToken = connectionSaSUtil.getSaSToken(uri, 60);
using (var httpClient = new HttpClient())
{
string json = JsonConvert.SerializeObject(deviceInstallation);
httpClient.DefaultRequestHeaders.Add("Authorization", SasToken);
var response = await httpClient.PutAsync(uri, new StringContent(json, System.Text.Encoding.UTF8, "application/json"));
return response.StatusCode;
}
}
I'm trying to enable my app so that I can use the Notifications tab of the Additional Tools windows associated with the Windows Phone emulator.
E.g.:
I've enabled the simulation, and relaunched the app but the AppId, URI and other fields are not being populated.
How can I enable the app for push notifications so that these fields will be populated?
You need to register for push notifications. When you have a Push Notifications Channel the Notifications tab can then get the Push Notifications URI
public IAsyncOperation<ChannelAndWebResponse> OpenChannelAndUploadAsync(String url)
{
IAsyncOperation<PushNotificationChannel> channelOperation = PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
return ExecuteChannelOperation(channelOperation, url, MAIN_APP_TILE_KEY, true);
}
public IAsyncOperation<ChannelAndWebResponse> OpenChannelAndUploadAsync(String url, String inputItemId, bool isPrimaryTile)
{
IAsyncOperation<PushNotificationChannel> channelOperation;
if (isPrimaryTile)
{
channelOperation = PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync(inputItemId);
}
else
{
channelOperation = PushNotificationChannelManager.CreatePushNotificationChannelForSecondaryTileAsync(inputItemId);
}
return ExecuteChannelOperation(channelOperation, url, inputItemId, isPrimaryTile);
}
private IAsyncOperation<ChannelAndWebResponse> ExecuteChannelOperation(IAsyncOperation<PushNotificationChannel> channelOperation, String url, String itemId, bool isPrimaryTile)
{
return channelOperation.AsTask().ContinueWith<ChannelAndWebResponse>(
(Task<PushNotificationChannel> channelTask) =>
{
PushNotificationChannel newChannel = channelTask.Result;
String webResponse = "URI already uploaded";
// Upload the channel URI if the client hasn't recorded sending the same uri to the server
UrlData dataForItem = TryGetUrlData(itemId);
if (dataForItem == null || newChannel.Uri != dataForItem.ChannelUri)
{
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
byte[] channelUriInBytes = Encoding.UTF8.GetBytes("ChannelUri=" + WebUtility.UrlEncode(newChannel.Uri) + "&ItemId=" + WebUtility.UrlEncode(itemId));
Task<Stream> requestTask = webRequest.GetRequestStreamAsync();
using (Stream requestStream = requestTask.Result)
{
requestStream.Write(channelUriInBytes, 0, channelUriInBytes.Length);
}
Task<WebResponse> responseTask = webRequest.GetResponseAsync();
using (StreamReader requestReader = new StreamReader(responseTask.Result.GetResponseStream()))
{
webResponse = requestReader.ReadToEnd();
}
}
// Only update the data on the client if uploading the channel URI succeeds.
// If it fails, you may considered setting another AC task, trying again, etc.
// OpenChannelAndUploadAsync will throw an exception if upload fails
//https://db3.notify.windows.com/?token=AgYAAABRl%2fdFlmxVkJPDROr5LRwp4tRW0Hcp006ODyaAkBppfiPDsAW%2fNRqsaIc0UFw3DMA15C%2btvGwtkreUZrBLs9vxOxCWL0fYw%2ft2HDFuTDM4szMxFWGom6B3kkGMiPa4C1o%3d
UpdateUrl(url, newChannel.Uri, itemId, isPrimaryTile);
return new ChannelAndWebResponse { Channel = newChannel, WebResponse = webResponse };
}).AsAsyncOperation();
}
I am retrieving contacts from gmail using Google Data API. I have used below code:
string token = Request.QueryString["token"];
RequestSettings rs = new RequestSettings("myapp", token);
rs.AutoPaging = true;
List<string> lstEmails = new List<string>();
try
{
rs.AutoPaging = true;
ContactsRequest cr = new ContactsRequest(rs);
Feed<Contact> f = cr.GetContacts();
foreach (Contact e in f.Entries)
{
foreach (EMail email in e.Emails)
{
lstEmails.Add(email.Address);
}
}
}
catch
{
}
But it reads only 25 gmail contacts only
and it throws the following error:
Execution Failed: {https://www.google.com/m8/feeds/contacts/{email}/full?start-index=26&max-results=25}
but i want to get total contacts from gmail.
i'm writing a mail send method with javamail.
I can not understand why I get and error as: Recipient not set.
This is my code:
public static void sendMail(String to, String subj, String body, String attachmentName, byte[] attachment, String mime) throws Exception {
Properties p = System.getProperties();
Session session = Session.getInstance(p);
MimeMessage dummyMessage = new MimeMessage(session);
dummyMessage.setFrom(new InternetAddress(LovProvider.getOpzioni().get("mail.address")));
dummyMessage.setSubject(subj);
String[] tos = to.split(";");
Address[] tosAddr = new InternetAddress[tos.length];
for (int i = 0; i < tos.length; i++) {
tosAddr[i] = new InternetAddress(tos[i]);
}
dummyMessage.setRecipients(Message.RecipientType.TO, tosAddr);
Multipart mp = new MimeMultipart();
MimeBodyPart bp = new MimeBodyPart();
bp.setText(body);
mp.addBodyPart(bp);
if (attachmentName != null && attachment != null) {
DataSource dataSource = new ByteArrayDataSource(attachment, mime);
MimeBodyPart attachBodyPart = new MimeBodyPart();
attachBodyPart.setDataHandler(new DataHandler(dataSource));
attachBodyPart.setFileName(attachmentName);
mp.addBodyPart(attachBodyPart);
}
dummyMessage.setContent(mp);
//***** DEBUGGING here I find the recipient
sendMail(dummyMessage.getInputStream());
}
public static void sendMail(InputStream emlFile) throws Exception {
Properties props = System.getProperties();
props.put("mail.host", LovProvider.getOpzioni().get("mail.out.host"));
props.put("mail.transport.protocol", LovProvider.getOpzioni().get("mail.out.protocol"));
props.put("mail." + LovProvider.getOpzioni().get("mail.out.protocol") + ".port", LovProvider.getOpzioni().get("mail.out.port"));
Session mailSession = Session.getDefaultInstance(props, PasswordAuthentication.getAuth(LovProvider.getOpzioni().get("mail.out.user"), LovProvider.getOpzioni().get("mail.out.password")));
MimeMessage message = new MimeMessage(mailSession, emlFile);
//***** DEBUGGING here I CAN NOT find the recipient
Transport.send(message);
}
As I wrote in comments in debug mode i can see the recipient correctly set in the first part, whant i convert it to InputStream to the second method I can not find recipient anymore.
I can't debugging your code, but maybe this examples can help you:
Examples about sending/receiving mail via/from gmail
http://famulatus.com/component/search/?searchword=gmail&searchphrase=all&Itemid=9999