Send smtp email with Azure blob storage attachments

1 Introduction

Smtp is the most common protocol to send messages over the internet. Smtp stands for Simple Mail Transfer Protocol. Smtp messages are secured using SSL by default, so no need to worry about security.

Azure Blob storage is going to store unstructured data as binary files, text files, any type of data in the cloud. It can store an image, document or a video as a blob, simply as an object. You can select a specific tier to store your blobs by referring to the pricing models of Azure blob storage.

Let's see how we can store a file in Azure blob storage and send it using smtp email.

↑ Return to Top

2 Background

If you want to know how to send an email using smtp, Please go through this article, https://social.technet.microsoft.com/wiki/contents/articles/36282.c-create-a-simple-smtp-email-with-html-body.aspx

If you want to know how to send an email concurrently using a windows service, check this article, https://social.technet.microsoft.com/wiki/contents/articles/36288.how-to-fire-an-email-using-a-windows-service.aspx

↑ Return to Top

3 Store files in the blob storage

This article is going to describe how to store an image, text file and a video in azure blob storage,

↑ Return to Top

3.1 Create a storage account in Azure portal

Log in to Azure portal, https://portal.azure.com Click on More Services link as below, It will open up all available services in azure portal. click on Storage accounts

All storage accounts are displayed in here, currently this azure account doesn't have any storage accounts. Click on Create Storage accounts to create a new storage account.

Add a name to the storage account, in this example, it's *mailfilestore
*Deployment model is going to tell how your storage account is going to deploy and manage, select Resource manager as Deployment model, storage accounts created by Azure portal is deployed under Resource manager Deployment model, it has newer features in Azure, and accounts created by Azure classic portal is deployed under classic.
In Account kind, it says what type of a storage account you want to use, General purpose accounts are going to store blobs, files, tables and queues,If you select account type as blob storage, it stores only blobs.
If you select Blob storage as account type, it's going to disable premium performance, You need to go for premium performance, when you need low latency performance like accessing virtual machine disks and databases. In here we are going to access files stored in a storage, We don't need to access stored images very frequently like accessing a database, so go for standard performance, that's enough.
You need to select a way to replicate storage account to maintain high availability and durability. Replication copies your data into a same data center or another data center. Let's select default replication method, Read access geo redundant storage (RA-GRS), in this replication method, it's going to replicate data into multiple data centers and data reads can be performed in secondary data center as well.
In Access tier, you can specify how you can access stored data. You can select Hot Access tier for more frequent data access, Cool access tier for less frequent access data like backups. In this example, let's select Hot access tier.
Storage service encryption is going to protect your data using encryption within data center,
Select your subscription for storage account,
Create a new resource group or use an existing resource group. When you use a resource group, you can deploy and manage all your resources in that group separately. You can redeploy all your resources in that resource group into another location.
 select a region to store your storage account, let's select East Asia, since it's near to me

Go to storage account and search for Access Keys and copy connectionstring of key1 in access keys,
If you wonder why storage account has two access keys, Azure has recommended to regenerate access keys frequently in order to maintain security of your stored data. While you regenerating a one access key, you can use second access key to manage your storage without any issue, since you have two access keys.

↑ Return to Top

3.2 Let's add some code to save your files in blob storage

Create a console application in Visual studio, we want to store storage connection-string as a configuration in our application. Create a configuration setting in app.config file as below.

<appSettings>


<add key="StorageConnectionstring"
value="DefaultEndpointsProtocol=https;AccountName=mailfilestore;AccountKey=pO+lfN4ycIRtC7LncRjUynQ94/Qk0tKnNupYfaXMclH1NCqxwDMXa05PyqwZ0FVaWNgVfVARF4xvCKWq+POkSQ==;EndpointSuffix=core.windows.net"/>

Create a class to handle blob storage saving, In this example PropertyHandler class is going to do that. In PropertyHandler class, initialize a private variable to hold the storage connection string


 private static  string storagekey = ConfigurationManager.AppSettings["StorageConnectionstring"]; 

Create a method to save to blob storage, and create an Azure storage account by passing storage key parameter,


public static  void SaveBlobs ()
{
  var storageAccount = CloudStorageAccount.Parse(storagekey); 

Create blob service client using azure storage account,


//create blob service client 
var blobClient = storageAccount.CreateCloudBlobClient();

add a configuration into app.config file to define the container,


 <add  key="container" value="testcontainer"/>

Define a container name to store files in azure storage account


 private static  string containerstring = ConfigurationManager.AppSettings["container"];

Create a reference to the container like this,


 var container = blobClient.GetContainerReference(containerstring);

Create blob container if it doesn't exist,

//create blob container 
container.CreateIfNotExists();

Set container permission to public, so any client can read your blob data, if you want to change access level, modify access policies on blob storage

 container.SetPermissions( new  BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });

Go to created storage account and click on Overview section and you can see available containers, you'll see container you created as below, check access type of the container, it's *Blob type


*

↑ Return to Top

3.2.1 Save image to a blob storage

Let's add more coding to save an image to a blob storage,

Create a configuration to hold image path in app.config file,

 <add key="imagePath" value="C:\store\images.jpg"/>

access imagepath to get path of an image, get file extension and append it to the file name.

string filePath = ConfigurationManager.AppSettings["imagePath"];
var extension = Path.GetExtension(filePath);
 
var filename = "image" + extension;

Get a reference to blob container,

//Get a reference to block blob container
 var blockBlob = container.GetBlockBlobReference(filename);

upload image to blob storage, don't forget to set the content type of the image as jpeg, and update blob properties after that.


using (var stream = File.OpenRead(filePath))
{
//upload file stream to block blob
blockBlob.UploadFromStream(stream);
blockBlob.Properties.ContentType = "image/jpeg";
blockBlob.SetProperties();
}

You can see complete code to save an image to a blob storage,


#region Save Image to a blob
 
string filePath = ConfigurationManager.AppSettings["imagePath"];
var extension = Path.GetExtension(filePath);
var filename = "image" + extension;
 
//Get a reference to block blob container
var blockBlob = container.GetBlockBlobReference(filename);
 
using (var stream = File.OpenRead(filePath))
{
//upload file stream to block blob
blockBlob.UploadFromStream(stream);
blockBlob.Properties.ContentType = "image/jpeg";
blockBlob.SetProperties();
}

This code sample describes how to store a text file in blob storage, Get the configured file path, and store file in blob storage and set content type as text/plain


#region Save text file to a blob
 
filePath = ConfigurationManager.AppSettings["filePath"];
extension = Path.GetExtension(filePath);
filename = "file" + extension;
 
//Get a reference to block blob container
blockBlob = container.GetBlockBlobReference(filename);
using (var stream = File.OpenRead(filePath))
{
//upload file stream to block blob
blockBlob.UploadFromStream(stream);
blockBlob.Properties.ContentType = "text/plain";
blockBlob.SetProperties();
}
 
#endregion

You can save a video file to a blob storage as below,


#region Save video file to a blob
 
filePath = ConfigurationManager.AppSettings["vedioPath"];
extension = Path.GetExtension(filePath);
filename = "vedio" + extension;
 
//Get a reference to block blob container
blockBlob = container.GetBlockBlobReference(filename);
using (var stream = File.OpenRead(filePath))
{
//upload file stream to block blob
blockBlob.UploadFromStream(stream);
blockBlob.Properties.ContentType = "video/mpeg";
blockBlob.SetProperties();
}
 
#endregion

Go inside test container and view available files in it,

If you want to open one of this file, select a file and you can see the URL of it.

↑ Return to Top

4 Send email with stored files as attachments

Define configuration settings used to send an email,
In this example, used gmail server as email server with specific port. email from and to addresses are also defined as a configurable setting.


<add key="emailServer"  value="smtp.gmail.com"/>
<add key="emailPort" value="587"/>
<add key="emailCredentialUserName" value="hansamaligamage@gmail.com"/>
<add key="emailCredentialPassword" value=""/>
<add key="fromAddress" value="hansamaligamage@gmail.com"/>
<add key="mailTo" value="ham@tiqri.com"/>

Create a class to set email properties as below,


 class Email
    {
 
        public string  Subject { get; set; }
        public string[] MailRecipientsTo { get; set; }
        public string[] MailRecipientsCc { get; set; }
        public string  Content { get; set; }
        public Attachment Image { get; set; }
        public Attachment File { get; set; }
        public Attachment Vedio { get; set; }
 
    }

In sample application, create a separate class to send an email,


 public static  void SendEmail ()
       {
           Email email = new  Email();
 
           email.MailRecipientsTo = new  string[] { ConfigurationManager.AppSettings["mailTo"] };
           email.MailRecipientsCc = new  string[] { ConfigurationManager.AppSettings["mailTo"] };
 
           email.Subject = "test email";
           email.Content = "Hi, How are you doing ? "  + "<br/><br/>";

Get Azure storage account reference by passing storage account connection string, create the blob client and get a reference to storage container,


CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storagekey);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("testcontainer");

Get a reference to image, we stored in test container,


#region Image
CloudBlockBlob blob = container.GetBlockBlobReference("image.jpg");

Download file to memory stream, and set content type and create a new attachment object from it.


var stream = new  MemoryStream();
blob.DownloadToStream(stream);
stream.Seek(0, SeekOrigin.Begin);
ContentType content = new  ContentType(MediaTypeNames.Image.Jpeg);
email.Image = new  Attachment(stream, content);

As same as image, create a new attachment from text file and set the content type as plain, if content type doesn't set properly, it will attach file as a invalid type of file.


#region text file
 
blob = container.GetBlockBlobReference("file.txt");
 
stream = new  MemoryStream();
blob.DownloadToStream(stream);
stream.Seek(0, SeekOrigin.Begin);
content = new  ContentType(MediaTypeNames.Text.Plain);
email.File = new  Attachment(stream, content);
 
#endregion

create the video attachment as well,


 #region vedio file
 
 blob = container.GetBlockBlobReference("vedio.mp4");
 
  stream = new  MemoryStream();
  blob.DownloadToStream(stream);
  stream.Seek(0, SeekOrigin.Begin);
  content = new  ContentType("video/mpeg");
  email.Vedio = new  Attachment(stream, content);
 
  #endregion
 
  SendMail(email);

Create a method to send email as below, its going to construct the email and sends it


 private static  void SendMail(Email email)
  {
     try
        {
             SmtpClient smtpClient = EmailClientBuilder();
             var emailMessage = MessageBuilder(email);
             smtpClient.Send(emailMessage);
         }
        catch (Exception ex)
         {
             throw ex;
          }
      }

Create a method to return smtp client object, initialize a smtp client instance and set email configurations as below.


 private static  SmtpClient EmailClientBuilder()
       {
           string emailServer = ConfigurationManager.AppSettings["emailServer"];
           int emailPort = Convert.ToInt32(ConfigurationManager.AppSettings["emailPort"]);
           string emailCredentialUserName = ConfigurationManager.AppSettings["emailCredentialUserName"];
           string emailCredentialPassword = ConfigurationManager.AppSettings["emailCredentialPassword"];
           SmtpClient smtpClient = new  SmtpClient(emailServer, emailPort);
           smtpClient.UseDefaultCredentials = false;
           smtpClient.Credentials = new  System.Net.NetworkCredential(emailCredentialUserName, emailCredentialPassword);
           smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
           smtpClient.EnableSsl = true;
           return smtpClient;
       }

In Message Builder method, populate MailMessage object using Email object we constructed earlier.


 private static  MailMessage MessageBuilder(Email email)
        {
            string fromAddress = ConfigurationManager.AppSettings["fromAddress"];
 
            MailMessage mail = new  MailMessage();
            mail.From = new  MailAddress(fromAddress);
            mail.Body = email.Content;
            mail.Subject = email.Subject;
            mail.IsBodyHtml = true;
 
            if (email.Image != null)
                mail.Attachments.Add(email.Image);
            if (email.File != null)
                mail.Attachments.Add(email.File);
            if (email.Vedio != null)
                mail.Attachments.Add(email.Vedio);
 
            foreach (var mailRecipient in email.MailRecipientsTo)
            {
                mail.To.Add(new MailAddress(mailRecipient));
            }
 
            return mail;
        }

↑ Return to Top

5 Download

You can download the source code from Microsoft tech net gallery, https://gallery.technet.microsoft.com/Azure-blob-storage-files-985136db?redir=0

↑ Return to Top

5.2 GitHub

You can clone git hub repository from here, https://github.com/hansamaligamage/blobstorageemailattatchment

↑ Return to Top

6 Conclusion

This article has explained how to store a text file, image and video in Azure blob storage, Then how to attach blobs as an attachment to smtp email

↑ Return to Top

7 See Also

↑ Return to Top

8 References

↑ Return to Top