Azure Functions: Sendgrid & NET Core

In questo (lungo) articolo desidero mostrarvi come utilizzando le Azure Functions scritte in NETCore sia possibile inviare mail con SendGrid in modalita’ praticamente quasi trasparente.

Prima di partire, cosa vi occore?

Vi occorre semplicemente una API KEY di SendGrid e potrete ottenerla generandola dal vostro account.

Quale caso pratico verra’ mostrato nell’esempio? Iporizziamo di volere mandare a tutti i nuovi iscritti al nostro sito una mail di benvenuto sfruttando le Azure Functions & SendGrid.

Cosa utilizzeremo per fare questo?

  • Azure Functions
  • SendGrid
  • Azure Queue
  • Dependency Injection: File Startup.cs
  • local.settings.json

Da dove partiamo? La carne al fuoco e’ tanta …

local.settings.json

Vi ricordate la API KEY generata in precedenza? Ora dobbiamo utilizzarla.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet", 
    "SendGridApiKeyValue": "SG[...]sI",
	"SendGridEmailTitle" : "Welcome New User ...",
	"SendGridEmailFromAddress" : "noreply@ ... .it",
	"SendGridEmailFromName" : "My Portal"
  }
}

Come avrete notato tra le voci e’ presente SendGridApiKeyValue ed il valore da assegnare e’ quello ottenuto dal portale di SendGrid. Le altre chiavi verranno utilizzate in seguito per l’invio della mail.

Startup.cs

Per inviare le mail tramite Function dobbiamo partire dal file Startup. Come mai? In questo modo andremo ad inserire nei Services la configurazione per utilizzare SendGrid.

File Startup.cs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public override void Configure(IFunctionsHostBuilder builder)
{
	//Read local.setting.json
	var config = new ConfigurationBuilder()
		.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
		.AddEnvironmentVariables()
		.Build();

	builder.Services.AddSingleton<SendGridConfigurationDTO>
	(
		s => new SendGridConfigurationDTO()
		{
			EmailTitle = config["SendGridEmailTitle"],
			EmailFromAddress = config["SendGridEmailFromAddress"],
			EmailFromName = config["SendGridEmailFromName"],
		}
	) ;
}

DOMANDA: Scusa Andrea, non hai utilizzato SendGridApiKeyValue o mi sbaglio? Tranquilli adesso arriviamo ad utilizzare anche il valore di SendGridApiKeyValue nel codice.

File SendGridConfigurationDTO.cs:

Quando abbiamo aggiunto nei service la configurazione per le Email da inviare abbiamo utilizzato SendGridConfigurationDTO ed ecco la sua definizione come classe.

1
2
3
4
5
6
7
public class SendGridConfigurationDTO
{
	
	public string EmailTitle { get; set; }
	public string EmailFromAddress { get; set; }
	public string EmailFromName { get; set; }
}

Azure Queue

Prima di entrare nel vivo della Azure Functions, vi informo che dovrete avere a dispozione una coda per inserire dei messaggi. Questo messaggio dovra’ contenere in modalita’ JSON la serializzazione di un oggetto di tipo CustomerHeader.

1
2
3
4
5
6
public class CustomerHeader
{
	public Guid Id { get; set; }
	public string Name { get; set; }
	public string Email { get; set; }
}

Un esempio?

1
2
3
4
5
{
	"Id":"9096220a-9fb1-4fda-ba9d-aa7d15ca5e9e",
	"Name":"Andrea",
	"Email":"mail@ ... .it"
}

Ora vi manca l’ultima informazione. Ogni Azure Queue ha un nome univoco all’interno dello stesso Account Storage. Per questo esempio la coda che andro’ ad utilizzare avra’ il nome di welcomecustomer.

Tips: Vuoi vedere come creare un JSON in modalita’ differenti tramite C#? Leggi Azure Functions: Creare un JSON sfruttando le ActionResults

Azure Functions

Facendo un breve riassunto dovremmo avere tutto.

  • La SendGridApiKeyValue
  • La Azure Queue sul nostro storage
  • I nostri DTO per la configurazioni e dettagli Header dell’utente

Pronti ad entrare nel vivo del codice? Cominciamo col creare la nostra classe dal nome SendGridDispatchFunction e predisponiamola per utilizzare le Dependency Injection.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class SendGridDispatchFunction
{
	private readonly SendGridConfigurationDTO _configuration = null;

	public SendGridDispatchFunction(SendGridConfigurationDTO configuration)
	{
		_configuration = configuration;
	}

}

A questo punto cosa manca? La parte principale ovvero la nostra Azure Function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[FunctionName("SendGridDispatchFunction")]
[return: SendGrid(ApiKey = "SendGridApiKeyValue")]
public SendGridMessage Run([QueueTrigger("welcomecustomer")] CustomerHeader customer, ILogger log)
{
	SendGridMessage message = new SendGridMessage()
	{
		Subject = _configuration.EmailTitle,
		From = new EmailAddress(_configuration.EmailFromAddress, _configuration.EmailFromName),                                 
	};

	message.AddTo(customer.Email, customer.Name);

	// Get more Customer info from DB --> use customer.Id

	message.HtmlContent = $"Hi <b>{customer.Name}</b> ... Have a good cloud day! (HTML Mode)";
	message.PlainTextContent = $"Hi {customer.Name} ... Have a good cloud day! (Plain Text Mode)";

	return message;
}

Ora veniamo al sodo. Come funziona questa Function? Si tratta di una Azure Functions che lavora su QueueTrigger. Quando nella coda verra’ inserito il messaggio la function lo prendera’ in pasto, rielaborera’ il tutto ed inviera’ la mail.

Come?

  • La function costruisce un SendGridMessage ed una volta completato lo utilizzera’ come valore di ritorno.
  • Se guardate bene la definizione della function troverete [return: e questo significa il valore di ritorno sara’ utilizzato
  • In questo caso chiamaremo SendGrid passando la ApiKey definita nel setting SendGridApiKeyValue nei passaggi iniziali
  • Non vi resta che attendere qualche minuto e la mail di prova arrivera’ a destinazione.

Tips:

In una serie di contesti lavorativi mi sono trovato la necessita’ di inviare in blocco tutte le mail ad un determinato orario. Sappiate che in questa modalita’ di lavoro (per come ho proposto il codice) esce tutto o quasi gratis. Come? Sappiate che avete due possibilita’ per farlo:

  • Nel momento in cui inserite un messaggio in welcomecustomer potete definirgli l’orario di attivazione
  • Una delle proprieta’ presenti in SendGridMessage e’ SendAt e questo vi consente di impostare l’orario di invio (Gets or sets a unix timestamp allowing you to specify when you want your email to be sent from SendGrid. This is not necessary if you want the email to be sent at the time of your API request.)

Semplice? Questa volta lo ammetto, ho esagerato ed ho scritto davvero tanto e dal contenuto non propriamente scontato. Se avete dubbi, cercatemi su Linkedin, magari riesco ad aiutarvi.