Email sending with SendGrid using WebJobs - c#

I'm trying to integrate SendGrid to a .Net 4.5 application using WebJobs.
I made the basic configurations required to send a basic email. I'm trying to run and test it in my local machine. I can't figure out how to push messages to the queue. I can't upgrade the .Net version of the application as of now. If it is possible to do this without using webjobs that is also fine.
Program.cs
static void Main()
{
var config = new JobHostConfiguration();
config.UseTimers();
config.Queues.MaxDequeueCount = 2;
config.Queues.MaxPollingInterval = TimeSpan.FromSeconds(4);
config.Queues.BatchSize = 2;
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}
config.UseSendGrid();
var host = new JobHost(config);
host.RunAndBlock();
}
Functions.cs
public static void ProcessQueueMessage([QueueTrigger("queue")] string message, TextWriter log, [SendGrid(From = "no-reply#company.com", To = "employee#company.com")] out Mail mail)
{
log.WriteLine(message);
mail = new Mail();
var personalization = new Personalization();
personalization.AddBcc(new Email("employee#company.com"));
mail.AddPersonalization(personalization);
mail.Subject = "Test Email Subject";
mail.AddContent(new Content("text/html", $"The message '{message}' was successfully processed."));
}
Found the following functions:
SendGrid_Test_002.Functions.ProcessQueueMessage
ServicePointManager.DefaultConnectionLimit is set to the default value of 2. This can limit the connection throughput to services like Azure Storage. For more information, see https://aka.ms/webjobs-connections.
Job host started
I get this on the console.
Thanks in advance :)

I just had to feed the messages into the webjob queue using the following code.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the queue client.
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
// Retrieve a reference to a container.
CloudQueue queue = queueClient.GetQueueReference("email-queue-name");
// Create the queue if it doesn't already exist
queue.CreateIfNotExists();
// Create message to be sent to the queue
CloudQueueMessage message = new CloudQueueMessage(JsonConvert.SerializeObject(new
{
From = emailContent.From,
To = emailContent.To,
Cc = emailContent.Cc,
Bcc = emailContent.Bcc,
Subject = emailContent.Subject,
Message = emailContent.Message
}).ToString());
queue.AddMessage(message);

Related

Using C# REST API to send TriggeredSend email - created in Content Builder in SFMC in C# code

I am totally new to SalesForce Marketing cloud.
We have a “Triggered Send” created using “Content Builder” with an email body with HTML attribuites. For eg. %%=v(#EVENT)=%% Invitation
There is a Customer_key for this TriggerSendDefinition
I am using FuelSDK – to TriggerSend this email.
I have NUget Package manager install Fuel SDK in my Visual studio 2019 project.
The App.config has the “clientId” and “clientSecret” values in the FuelSDK config section.
Here is my code below.
public void TestInvitationSend(string CustomerKey)
{
string myName = "John Adams";
string myEvent = "13989";
string fullurl = baseAPIAuthURL + AuthTokenUrl; // Values passed in
NameValueCollection parameters = new NameValueCollection();
parameters.Add("clientId", clientId);
parameters.Add("clientSecret",clientSecret);
parameters.Add("accountId", "account123");
**ETClient myclient = new ETClient(parameters);**
TriggeredSendDefinition definition = new TriggeredSendDefinition();
definition.CustomerKey = customerKey;
//subscriber to whom email is sent
Subscriber subscriber = new Subscriber();
subscriber.EmailAddress = myTest#test.com;
subscriber.SubscriberKey = myTest#test.com;
TriggeredSend triggeredsend = new TriggeredSend();
triggeredsend.TriggeredSendDefinition = definition;
triggeredsend.AuthStub = myclient;
triggeredsend.CustomerKey = customerKey;
triggeredsend.Subscribers = new Subscriber[] { subscriber };
SendReturn results = triggeredsend.Send();
Console.WriteLine("Send Status: " + results.Status.ToString());
}
I am getting a 404 error at the line in “bold” when initializing myClient and unable to pass-in values dynamically. Could not find much documentation for email send through code.
Can you point me to some examples of TriggerSend emails using REST API ?
Thanks

Get Azure service bus queue status using NServiceBus

https://stackoverflow.com/a/50267687/2063755 provides the following code to get the queue status:
string connectionString = "connection string";
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
var queueDescription = namespaceManager.GetQueue("queue name");
var status = queueDescription.Status;
How can I do that using NServiceBus?
I was hoping to use IEndpointInstance but it doesn't have many methods.
NServiceBus doesn't provide queue status. If you need the status of the queue, you will have to use the native Azure Service Bus SDK and NamespaceManager or ServiceBusAdministrativeClient, depending on what SDK you're using.
The latest version of NServiceBus uses the Azure.Messaging.ServiceBus SDK. To read the status of a queue queue the following would be needed:
var admin = new ServiceBusAdministrationClient(connectionString);
QueueProperties props = await admin.GetQueueAsync("queue");
var status = props.Status

C# Console Application - Parsing Office 365 Inbox

I was able to succeed via a package I found called EAGetMail. Unfortunately, I realized soon after that they have a token system and this is not a free approach.
There are a couple other choices available, like using Outlook Mail REST API, and MimeKit, but I'm lost on how to achieve my end result because no "start to finish" code is available on either of these references that demonstrates how to parse an Inbox for an account.
I've started to write this with the help of Mimekit, but am not sure if this is the proper way at all.
I must imagine it looks something like:
using (var client = new SmtpClient ())
{
client.Connect("outlook.office365.com", 587);
client.Authenticate("myemail#office365account.com", "mypassword");
var message = MimeMessage.Load(stream);
}
I don't know how to setup the stream mentioned above, and I don't know if it's possible to do this with Mimekit and Office 365.
I'm open to seeing a solution for this in any other approach that's not through EAGetMail. If anyone has a lightweight solution ranging from actual establishing a connection, to pulling messages from the inbox, would be great to see!
I've got it using EWS (Exchange Web Services). Here's my code:
private static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
// The default for the validation callback is to reject the URL.
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
// Validate the contents of the redirection URL. In this simple validation
// callback, the redirection URL is considered valid if it is using HTTPS
// to encrypt the authentication credentials.
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
static void Main(string[] args)
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.Credentials = new WebCredentials("email#myemail.com", "myPassword");
service.AutodiscoverUrl("email#myemail.com", RedirectionUrlValidationCallback);
//creates an object that will represent the desired mailbox
Mailbox mb = new Mailbox(#"email#myemail.com");
//creates a folder object that will point to inbox folder
FolderId fid = new FolderId(WellKnownFolderName.Inbox, mb);
//this will bind the mailbox you're looking for using your service instance
Folder inbox = Folder.Bind(service, fid);
//load items from mailbox inbox folder
if (inbox != null)
{
FindItemsResults<Item> items = inbox.FindItems(new ItemView(100));
foreach (var item in items)
{
item.Load();
Console.WriteLine("Subject: " + item.Subject);
}
}
}

Azure C# Webjob TimeTrigger not firing

I'm attempting to create an Azure WebJob that will execute Functions.Methods on a set timer. I have setup a simple WebJob Project in VS2017 and added Microsoft.Azure.Webjobs.Extensions to allow me to reference Timers.
As a learning process, i'm attempting to create a WebJob that will call a Function Method to send an email to my address when the TimerTrigger Fires (send an email every 60 seconds for example)
My Main void looks like this:
public static void Main()
{
var config = new JobHostConfiguration();
config.Tracing.ConsoleLevel = System.Diagnostics.TraceLevel.Verbose;
config.UseTimers();
var host = new JobHost();
host.RunAndBlock();
}
The Function method i would like to call looks like this:
[NoAutomaticTrigger] //See below note on [NoAutomaticTrigger]
public static void SendMail([TimerTrigger("00:00:10", RunOnStartup = true)] TextWriter log)
{
log.WriteLine("[" + DateTime.Now.ToString() + "] Preparing to send Mail");
MailMessage Message = new MailMessage();
SmtpClient MailClient = new SmtpClient();
String FromAddress = "****";
String FromName = "****";
String Password = "****;
String ToAddress = "****";
MailClient.UseDefaultCredentials = false;
MailClient.Credentials = new System.Net.NetworkCredential(FromAddress, Password);
MailClient.Port = 587;
MailClient.Host = "****";
MailClient.DeliveryMethod = SmtpDeliveryMethod.Network;
MailClient.EnableSsl = true;
Message.To.Add(ToAddress);
Message.From = new MailAddress(FromAddress, FromName);
Message.Subject = "WebJob | Test Mail";
Message.Body = "TimerTrigger Function Sendmail triggered at: " + DateTime.Now.ToString();
MailClient.Send(Message);
log.WriteLine("[" + DateTime.Now.ToString() + "] Mail Successfully Sent");
}
Now if i Debug the above locally i see this
The SendMail Method Never fires.
Now if I upload this as a WebJob to azure, then navigate to WebJob Dashboard/Functions/Function Invocation Log and "Run Function" I receive an e-mail shortly after from My SendMail Method with the following output:
[5/20/2017 11:47:31 AM] Preparing to send Mail
[5/20/2017 11:47:32 AM] Mail Successfully Sent
RE: [NoAutomaticTrigger]
One suggestion I've had was to remove the [NoAutomaticTrigger] attribute from the SendMail Method as this tells the jobhost to ignore the timer but if I do this I get:
No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).
So the question is, how can I make my sendmail method fire on the specified [TimerTrigger] when running in Azure as a WebJob
Thanks in advance
So the question is, how can I make my sendmail method fire on the specified [TimerTrigger] when running in Azure as a WebJob
Based on your code, I found that you missed to pass the config parameter to JobHost.
var host = new JobHost(config);
In addition, the NoAutomaticTrigger attribute did need to be removed and the TimerTrigger attribute should be applied to a parameter whose type is TimerInfo. Code below is for your reference.
public static void SendMail([TimerTrigger("00:00:10")] TimerInfo timer, TextWriter log)
After that, the TimerTrigger will work.

ServiceBus throws 401 Unauthorized Error

I'm using a simple implementation of the Windows Service Bus 1.0 Brokered messaging to keep track of the user interactions with a particular web application.
Every time something is saved to a "sensitive" table in the database, I have setup the repository layer send a message like so:
ServiceBus.MessageQueue<T>.PushAsync(entity);
which will then serialize the entity and create a message out of it.
My MessageQueue class is something like this.
public static class MessageQueue<T>
{
static string ServerFQDN;
static int HttpPort = 9355;
static int TcpPort = 9354;
static string ServiceNamespace = "ServiceBusDefaultNamespace";
public static void PushAsync(T msg)
{
ServerFQDN = System.Net.Dns.GetHostEntry(string.Empty).HostName;
//Service Bus connection string
var connBuilder = new ServiceBusConnectionStringBuilder { ManagementPort = HttpPort, RuntimePort = TcpPort };
connBuilder.Endpoints.Add(new UriBuilder() { Scheme = "sb", Host = ServerFQDN, Path = ServiceNamespace }.Uri);
connBuilder.StsEndpoints.Add(new UriBuilder() { Scheme = "https", Host = ServerFQDN, Port = HttpPort, Path = ServiceNamespace}.Uri);
//Create a NamespaceManager instance (for management operations) and a MessagingFactory instance (for sending and receiving messages)
MessagingFactory messageFactory = MessagingFactory.CreateFromConnectionString(connBuilder.ToString());
NamespaceManager namespaceManager = NamespaceManager.CreateFromConnectionString(connBuilder.ToString());
if (namespaceManager == null)
{
Console.WriteLine("\nUnexpected Error");
return;
}
//create a new queue
string QueueName = "ServiceBusQueueSample";
if (!namespaceManager.QueueExists(QueueName))
{
namespaceManager.CreateQueue(QueueName);
}
try
{
QueueClient myQueueClient = messageFactory.CreateQueueClient(QueueName);
string aaa = JsonConvert.SerializeObject(msg, Formatting.Indented,
new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new NHibernateContractResolver()
});
BrokeredMessage sendMessage1 = new BrokeredMessage(aaa);
sendMessage1.Properties.Add("UserName",Thread.CurrentPrincipal.Identity.Name);
sendMessage1.Properties.Add("TimeStamp", ApplicationDateTime.Now);
sendMessage1.Properties.Add("Type", msg.GetType().Name);
myQueueClient.Send(sendMessage1);
}
catch (Exception e)
{
var l = new Logger();
l.Log(LogEventEnum.WebrequestFailure, e.Message);
Console.WriteLine("Unexpected exception {0}", e.ToString());
throw;
}
}
}
This works flawlessly when I debug this locally. But when I publish the site in IIS and run, the namespaceManager.QueueExists(QueueName) call fails with an exception which says "401 Unauthorized error".
When I change the Application pool identity (in IIS) to an admin account this error does not occur. However, there is absolutely no way that I can make this happen when we go production.
Am I missing something? If so, what is it? Any help is greatly appreciated.
Did you read the security section in the docs, Chameera? http://msdn.microsoft.com/en-us/library/windowsazure/jj193003(v=azure.10).aspx
You seem to be running with the default security settings, meaning you only have admin accounts authorized. Review the documentation section and grant the requisite rights to the accounts you want to use in prod.

Categories

Resources