Saturday, May 27, 2017

Send smtp email with Azure blob storage attatchments

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.

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

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,

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, used 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 accesing virtual machine disks and databses. In here we are going to access files stored in a storage, it's not very frequenly accessible, so go for standart performance, thats 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 centre or another data centre. 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 centres and data readds can be performed in secondary data centre 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 frequenly accessed data like backups. In this exmple, 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.

select a region to store your storage account, let's select East Asia, since it's near for me 😀







































Go to storage account and search for Access Keys and copy connection string 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 withourt any issue, since you have two access keys.















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 part, 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 the 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 the blob container if it doesnt 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













Save image to a blob storage

Let's add more coding to save an image to a blob storage,
Create a configuration to hold the image path in app.config file,






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

access imagepath to get the path of a image, get file extention 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 the blob container,







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


upload the 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 imgae to a blonb 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();
}

#endregion


This code sample describes how to store a text file into 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 testcontainer 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.








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="SavingHope2016"/>
<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 appliication, create a seperate class to hold send an email, create a method to send and email and create an instance from Email calss and set basic properties as below.












 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 connectionstring, 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 testcontainer,








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


Download file to a memeory stream, and set content type and create a new attatchment 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 attatchment from text file as well and set the content type as plain, if content type doesnt set properly, it will attatch the 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 attatchment 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 smtpclient object, initialize a smtpclient 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 MessageBuilder 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;
        }



Download

5.1 Tech Net Gallery

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

5.2 GitHub

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

Conclusion

Run the console application and check whether email is sent, You can see image, text file and video is attatched to the email as below. All the files are attatched with propert content types as we specified


In this article, We saw how to upload an image, text file and vedio to a blob storage and how to attatch them into a smtp mail message. Download the code sample and run it and see 

See Also


References

2 comments:

  1. This is a very nice article. thank you for publishing this. i can understand this easily..!!..Azure Online Training Hyderabad

    ReplyDelete
  2. Companies with massive amounts of data are always looking for new and innovative ways to leverage their data for insights and analysis. Too often, however, they’re held back by outdated IT infrastructures and the challenges of securing, collating, and analyzing all of their data in one place.Data Lakesare a great way to address these challenges.

    ReplyDelete