By Isidore Bennett Thursday, October 11, 2018 Updated: Wednesday, October 24, 2018 10:29:14 AM SAST



Scenario

So you know how to send an email using MVC but now you'd like to attach an invitation to a meeting or some fancy event to someone. We're gonna have a quick look into how to how to accomplish this and it should, hopefully, work for the bigger emailing apps like Outlook and Gmail.
This is my story.

Overview

In this snippet I will pick up from a previous full length article I published here. Above and beyond the technologies we used before, we'll be using an ICS... or an iCal... or an iCalendar... or an Internet Calendar (they're the same thing) format for our invitation.

Straight Into It

Before we start I'd like to say that when I had decided to write this short article I had sorely overestimated my, already lacking, skill in relation to the supposed straight forward nature of this topic when I was doing my research and development. And I was rightfully humbled, but I have overcome!

Since we're merely following from a previously posted article, we won't do much setting up of the project and you're even free to download and follow from the previous example. Don't worry, I'll be sure to include a link to download this complete project at the end.

EmailModel.cs

First we're going to update our Model so that it can hold the data needed for, what I believe, are the minimum requirements for an invitation.
Add the following code to the EmailModel.cs file:

  1. public string Location { get; set; }
  2. public DateTime StartTime { get; set; }
  3. public DateTime EndTime { get; set; }
  4. public DateTime Date { get; set; }
  5. public string Summary { get; set; }
  6. public string Description { get; set; }

The above code is pretty self-explanatory, maybe the public string Summary and the public string Description aren't. The one is kind of the name of the event/meeting/invitation/whatever and the other is or can be a lengthy description of the invitation respectively.

Your Model should bare a resemblance to this when you're done:

  1. public string Name { get; set; }
  2. public string Addess { get; set; }
  3. public string Subject { get; set; }
  4. public string Body { get; set; }
  5. public string Location { get; set; }
  6. public DateTime StartTime { get; set; }
  7. public DateTime EndTime { get; set; }
  8. public DateTime Date { get; set; }
  9. public string Summary { get; set; }
  10. public string Description { get; set; }

Now that our Model has been altered, we're now able to do the same with our View and we'll be able to more easily access our properties there.

Index.cshtml

Open the Index.cshtml View and add these lines of code after the form fields and before the submit button we had previously created:

  1. <label asp-for="Location">Location</label> <br />
  2. <input asp-for="Location" type="text" name="Location" /> <br />
  3. <label asp-for="Date">Date</label> <br />
  4. <input asp-for="Date" type="date" name="Date" /><br />
  5. <label asp-for="StartTime">Start Time</label> <br />
  6. <input asp-for="StartTime" type="time" name="StartTime" /><br />
  7. <label asp-for="EndTime">End Time</label> <br />
  8. <input asp-for="EndTime" type="time" name="EndTime" /><br />
  9. <label asp-for="Summary">Summary</label> <br />
  10. <input asp-for="Summary" type="text" name="Summary" /><br />
  11. <label asp-for="Description">Description</label> <br />
  12. <textarea asp-for="Description" type="" name="Description"></textarea> <br />

The last I checked, some form controls don't work as intented in IE. I think the date and time input fields work just like plain old text fields if I'm not mistaken.

With our View updated we should be able to get our data from it in our Controller when we post our form.

EmailController.cs

The more complex part is up next and the code is quite lengthy. I'd say I'll explain but some of the lines are waaaay over my head but I'll try my best to explain.

  1. DateTime date = emailModel.Date;
  2. DateTime startTime = emailModel.StartTime;
  3. DateTime endTime = emailModel.EndTime;
  4. string now = DateTime.Now.ToString("yyyyMMddTHHmmssZ");
  5. string ics = string.Format(
  6.  "BEGIN:VCALENDAR\r\n" +
  7.  "PRODID:-//Comapany & Co.//Their Application//EN\r\n" +
  8.  "VERSION:2.0\r\n" +
  9.  "METHOD:REQUEST\r\n" +
  10.  "BEGIN:VEVENT\r\n" +
  11.  "CREATED:{0}\r\n" +
  12.  "DTSTART:{1}\r\n" +
  13.  "DTEND:{2}\r\n" +
  14.  "DTSTAMP:{3}\r\n" +
  15.  "UID:{4}\r\n" +
  16.  "ATTENDEE;CN=\"{5}\";RSVP=TRUE:mailto:{6}\r\n" +
  17.  "X-ALT-DESC;FMTTYPE=text/html:{7}\r\n" +
  18.  "LOCATION:{8}\r\n" +
  19.  "ORGANIZER;CN=\"Mailer App Name Here\":mailto:[[The email address that the ivitation is being sent from]]\r\n" +
  20.  "SEQUENCE:0\r\n" +
  21.  "SUMMARY:{9}\r\n" +
  22.  "TRANSP:OPAQUE\r\n" +
  23.  "END:VEVENT\r\n" +
  24.  "END:VCALENDAR",
  25.  now,
  26.  string.Concat(date.Year, date.Month.ToString("D2"), date.Day.ToString("D2"), "T", startTime.Hour.ToString("D2"), startTime.Minute.ToString("D2"), startTime.Second.ToString("D2")),
  27.  string.Concat(date.Year, date.Month.ToString("D2"), date.Day.ToString("D2"), "T", endTime.Hour.ToString("D2"), endTime.Minute.ToString("D2"), endTime.Second.ToString("D2")),
  28.  now,
  29.  Guid.NewGuid(),
  30.  emailModel.Name,
  31.  emailModel.Addess,
  32.  emailModel.Description,
  33.  emailModel.Location,
  34.  emailModel.Summary);
  35. ContentType contentType = new ContentType("text/calendar");
  36. contentType.Parameters.Add("method", "REQUEST");
  37. contentType.Parameters.Add("name", "invitation.ics");
  38. byte[] bytes = Encoding.UTF8.GetBytes(ics);
  39. MemoryStream stream = new MemoryStream(bytes);
  40. Attachment icsAttachment = new Attachment(stream, "invitation.ics", "text/calendar");
  41. mailMessage.Attachments.Add(icsAttachment);

Okay okay, 40+ lines of code is a bit excessive to stomach in one sitting but lines 7 - 25 is what we really came here for. These lines are where we're building our ical file. Directly below I'll list and have a link to what most of these properties are if you're extra curious.

Property List

When I was doing some research this site really helped me understand. The links below reside within it.

I couldn't find X-ALT-DESC so I'm not sure if it was added after the initial specification. But I've linked it anyway.

I'm gonna skip some lines when it comes to the explanation of the Properties (lines 7 - 25) but you're free to follow the links I provided above if you're feeling a little uncertain.

  • In lines 1 - 3 we're just assigning our dates and times to variables to lessen the mess that will come later.
  • Line 4 we're setting the date/time format because the ical format is extremely specific. Dates need to adhere to this format: yyyyMMddTHHmmssZ.
  • In line 6 we're creating our string, if you prefer StringBuilder and appending new lines then it will still work.
  • Line 7 is where we start or open our ical.
  • Line 17 is where we say who's attending. If you're sending an invitation to multiple recipients you'll have to write this line out for each recipient. You can accomplish this with some kind of looping function to iterate through each one. Also take note of the RSVP=TRUE if you're interested in requesting a response.
  • In place of line 18, I've seen examples of DESCRIPTION instead of X-ALT-DESC. Apparently it allows for HTML.
  • Line 20 you need to note that if the emails for Attendee and Organizer are the same, the Organizer won't be able to accept (obvious I know but it took me longer than I want to admit to figure that out).

It won't be enought to just add \n at the end of each line (lines 7 - 24) because it won't adhere to the format specifications so be sure to use \n\r.

  • Lines 27 and 28 is a bit messing because we want to get the date of the meeting as well as the start and end times and also format it in the yyyyMMddTHHmmssZ format.
  • Lines 37 - 39 are SUPER important and I've struggled to understand why the .ics file was only attached but the email itself wasn't recognized as an invitation. This article saved my life. You need to specify that what you're sending is of type text/calendar.
  • Lines 40 - 44 is where we build and attached our ical in .ics format.

Full Code

Below is the full code for the EmailController.cs.

  1. using Email_Invitation_MVC.Models;
  2. using Microsoft.AspNetCore.Mvc;
  3. using System;
  4. using System.IO;
  5. using System.Net;
  6. using System.Net.Mail;
  7. using System.Net.Mime;
  8. using System.Text;
  9. namespace Email_Invitation_MVC.Controllers
  10. {
  11.  public class EmailController : Controller
  12.  {
  13.   public IActionResult Index()
  14.   {
  15.     return View();
  16.   }
  17.   
  18.   [HttpPost]
  19.   public IActionResult Index(EmailModel emailModel)
  20.   {
  21.    if (ModelState.IsValid)
  22.    {
  23.     try
  24.     {
  25.      SmtpClient smtpClient = new SmtpClient("smtp.gmail.com", 587);
  26.      MailMessage mailMessage = new MailMessage();
  27.      smtpClient.Credentials = new NetworkCredential
  28.      {
  29.       UserName = "[[Your email address here]]",
  30.       Password = "[[Aboves email address password here]]"
  31.      };
  32.      
  33.      smtpClient.EnableSsl = true;
  34.      smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
  35.      
  36.      mailMessage.From = new MailAddress("[[Your email address here]]");
  37.      mailMessage.To.Add(emailModel.Addess);
  38.      mailMessage.Subject = emailModel.Subject;
  39.      mailMessage.Body = string.Format("{0} has sent you an email, their email address: {1}.\n\n" +
  40.       "They had this to say: \n\"{2}\"", emailModel.Name, emailModel.Addess, emailModel.Body);
  41.      //Invitation
  42.      DateTime date = emailModel.Date;
  43.      DateTime startTime = emailModel.StartTime;
  44.      DateTime endTime = emailModel.EndTime;
  45.      string now = DateTime.Now.ToString("yyyyMMddTHHmmssZ");
  46.      string ics = string.Format(
  47.       "BEGIN:VCALENDAR\r\n" +
  48.       "PRODID:-//Comapany & Co.//Their Application//EN\r\n" +
  49.       "VERSION:2.0\r\n" +
  50.       "METHOD:REQUEST\r\n" +
  51.       "BEGIN:VEVENT\r\n" +
  52.       "CREATED:{0}\r\n" +
  53.       "DTSTART:{1}\r\n" +
  54.       "DTEND:{2}\r\n" +
  55.       "DTSTAMP:{3}\r\n" +
  56.       "UID:{4}\r\n" +
  57.       "ATTENDEE;CN=\"{5}\";RSVP=TRUE:mailto:{6}\r\n" +
  58.       "X-ALT-DESC;FMTTYPE=text/html:{7}\r\n" +
  59.       "LOCATION:{8}\r\n" +
  60.       "ORGANIZER;CN=\"Mailer App Name Here\":mailto:[[The email address that the ivitation is being sent from]]\r\n" +
  61.       "SEQUENCE:0\r\n" +
  62.       "SUMMARY:{9}\r\n" +
  63.       "TRANSP:OPAQUE\r\n" +
  64.       "END:VEVENT\r\n" +
  65.       "END:VCALENDAR",
  66.       now,
  67.       string.Concat(date.Year, date.Month.ToString("D2"), date.Day.ToString("D2"), "T", startTime.Hour.ToString("D2"), startTime.Minute.ToString("D2"), startTime.Second.ToString("D2")),
  68.       string.Concat(date.Year, date.Month.ToString("D2"), date.Day.ToString("D2"), "T", endTime.Hour.ToString("D2"), endTime.Minute.ToString("D2"), endTime.Second.ToString("D2")),
  69.       now,
  70.       Guid.NewGuid(),
  71.       emailModel.Name,
  72.       emailModel.Addess,
  73.       emailModel.Description,
  74.       emailModel.Location,
  75.       emailModel.Summary);
  76.      ContentType contentType = new ContentType("text/calendar");
  77.      contentType.Parameters.Add("method", "REQUEST");
  78.      contentType.Parameters.Add("name", "invitation.ics");
  79.      byte[] bytes = Encoding.UTF8.GetBytes(ics);
  80.      MemoryStream stream = new MemoryStream(bytes);
  81.      Attachment icsAttachment = new Attachment(stream, "invitation.ics", "text/calendar");
  82.      mailMessage.Attachments.Add(icsAttachment);
  83.      smtpClient.Send(mailMessage);
  84.     }
  85.     catch (Exception e)
  86.     {
  87.      ViewBag.EmailError = ("Error: {0}", e);
  88.     }
  89.    }
  90.    return View();
  91.   }
  92.  }
  93. }

You can validate your .ics files at iCalendar Validator if you're having a hard time getting the format right.

I hope this follow up on my previous article proved insightful and that you've learned as much as I did. Please feel free to comment and ask any questions or even leave suggestions.
Thanks for reading.

Plain Email Project
Invitation Email Project

Privacy Policy