I have built a calendar management system in SharePoint on top of SharePoint calendar.
One of the functionalities it offers to users is to add the event to outlook as a meeting. I had built 'add to outlook' i.e. outlook meeting invite functionality using downloading event in ICS file and it works fine but users have to click many times since ICS file would download, then open in outlook, save in outlook, etc. This time, I wanted to offer more efficient solution so users don't have to click multiple times.
So i came up with sending event invitation to users as an outlook meeting invite. No Clicks!
Below is how i did it:
Problem-Scenario:
Programmatically send Outlook meeting invite from SharePoint
Solution:
Here, I will cover only the part where you send Outlook meeting invite programmatically.
//Read comments for details:
//Replace Constants.variable name with your variable value.
//Replace event item column values with your item values.
public void SendMeetingInviteEmail(SPListItem currentItem)
{
string currentUserEmailAddress = SPContext.Current.Web.CurrentUser.Email;
string currentUserDisplayName = SPContext.Current.Web.CurrentUser.Name;
//get all event columns and store them in variables. Easy step, so removed code for it.
//......//
//Create Mail Message object with required details
MailMessage msg = new MailMessage();
msg.From = new MailAddress(Constants.EventsAdminEmailAddress, Constants.EventsAdminDisplayName);
msg.To.Add(new MailAddress("steve@apple.com", "steve jobs"));
// CC is optional
msg.CC.Add(new MailAddress("amigo@spanish.com", "Amigo Friend"));
msg.Subject = eventTitle; //from event item
msg.Body = eventPresenter + eventDescriptionAsText; //from event item
msg.Headers.Add("Content-class", "urn:content-classes:calendarmessage");
/* Most important part is to create alternate views:
You need to create two alternate views. One for calendar (mandatory) and another one for the mail body. (optional)
I highly recommend creating both views even if second one is optional.
If you don't create a separate alternate view for mail body, it will be simple text with no HTML whatsoever. So it will be a straight line. Users are not going to like that.
Mail body alternate view will allow the body to be sent as html.
*/
//Calendar Alternate View (mandatory)
StringBuilder str = new StringBuilder();
str.AppendLine("BEGIN:VCALENDAR");
str.AppendLine("PRODID:-//Schedule a Meeting");//no need to change to SharePoint ID
str.AppendLine("VERSION:2.0");
str.AppendLine("METHOD:REQUEST");
str.AppendLine("BEGIN:VEVENT");
str.AppendLine("CLASS:PUBLIC");
/*All date time objects should be in UTC format else the meeting invite will break.
Most probably this is an Outlook meeting requirement
eventStartTime and eventEndTime objects are converted into UTC format.
You may ask how to do it, so here is an example:
eventStartTime = DateTimeOffset.Parse(currentItem[Constants.EventsListFieldStartTime].ToString()).UtcDateTime;
*/
str.AppendLine(string.Format("CREATED:{0:yyyyMMddTHHmmss}", DateTime.Now));
str.AppendLine(string.Format("DTSTART:{0:yyyyMMddTHHmmssZ}", eventStartTime));
str.AppendLine(string.Format("DTSTAMP:{0:yyyyMMddTHHmmssZ}", DateTime.UtcNow));
str.AppendLine(string.Format("DTEND:{0:yyyyMMddTHHmmssZ}", eventEndTime));
str.AppendLine(string.Format("LOCATION:{0}", eventLocation));
str.AppendLine(string.Format("UID:{0}", Guid.NewGuid().ToString()));
str.AppendLine(string.Format("DESCRIPTION:{0}", msg.Body));
str.AppendLine(string.Format("X-ALT-DESC;FMTTYPE=text/html:{0}", msg.Body));
str.AppendLine(string.Format("SUMMARY;LANGUAGE=en-us: Scheduled for {0}", msg.Subject));
str.AppendLine(string.Format("ORGANIZER:MAILTO:{0}", msg.From.Address));
/*
Below is how we create meeting alert for user.
TRIGGER:-PT15M
It means that user alert will activate 15 minutes before the meeting starting time.
You can change it based on your requirements
*/
str.AppendLine("BEGIN:VALARM");
str.AppendLine("TRIGGER:-PT15M");
str.AppendLine("ACTION:DISPLAY");
str.AppendLine("DESCRIPTION:Reminder");
str.AppendLine("END:VALARM");
str.AppendLine("END:VEVENT");
str.AppendLine("END:VCALENDAR");
string eventsHomeUrl = SPContext.Current.Site.Url + Constants.EventsWebUrl;
SmtpClient smtpclient = new SmtpClient(GetSMTPHostName(eventsHomeUrl));
smtpclient.Credentials = CredentialCache.DefaultNetworkCredentials;
//add mail body HTML type alternate view
ContentType HtmlCtype = new ContentType("text/html");
//eventPresenter and eventDescription are event item column values
string bodyHtml = GetBodyHtml(eventPresenter + "<br>" + eventDescription);
AlternateView HtmlView = AlternateView.CreateAlternateViewFromString(bodyHtml, HtmlCtype);
msg.AlternateViews.Add(HtmlView);
//REMEMBER to add Calendar view last / all other views before it else Outlook invite won't work
ContentType contype = new ContentType("text/calendar");
contype.Parameters.Add("method", "REQUEST");
AlternateView avCal = AlternateView.CreateAlternateViewFromString(str.ToString(), contype);
msg.AlternateViews.Add(avCal);
smtpclient.Send(msg);
}
/*
Get SMTP host name from SharePoint outgoing e-mail settings. Good practice to set it at web application level.
*/
private static string GetSMTPHostName(string siteUrl)
{
using (SPSite site = new SPSite(siteUrl))
{
//Get the SMTP host name from “Outgoing e-mail settings”
return site.WebApplication.OutboundMailServiceInstance.Parent.Name;
}
}
/*
Last but not least is how to create mail body. It is self explanatory. See below:
*/
private static string GetBodyHtml(string body)
{
string bodyHtml =
@"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 3.2//EN"">"
+ @"<HTML>"
+ @"<HEAD>"
+ @"<META HTTP-EQUIV=""Content-Type"" CONTENT=""text/html; charset=utf-8"">"
+ @"<META NAME=""Generator"" CONTENT=""MS Exchange Server version 6.5.7652.24"">"
//+ @"<TITLE>{0}</TITLE>"
+ @"</HEAD>"
+ @"<BODY>"
+ @"<BR>"
+ @"{0}"
+ @"</BODY>"
+ @"</HTML>";
return String.Format(bodyHtml, body);
}
Do comment if this blog has helped you!
Solution:
Here, I will cover only the part where you send Outlook meeting invite programmatically.
//Read comments for details:
//Replace Constants.variable name with your variable value.
//Replace event item column values with your item values.
public void SendMeetingInviteEmail(SPListItem currentItem)
{
string currentUserEmailAddress = SPContext.Current.Web.CurrentUser.Email;
string currentUserDisplayName = SPContext.Current.Web.CurrentUser.Name;
//get all event columns and store them in variables. Easy step, so removed code for it.
//......//
//Create Mail Message object with required details
MailMessage msg = new MailMessage();
msg.From = new MailAddress(Constants.EventsAdminEmailAddress, Constants.EventsAdminDisplayName);
msg.To.Add(new MailAddress("steve@apple.com", "steve jobs"));
// CC is optional
msg.CC.Add(new MailAddress("amigo@spanish.com", "Amigo Friend"));
msg.Subject = eventTitle; //from event item
msg.Body = eventPresenter + eventDescriptionAsText; //from event item
msg.Headers.Add("Content-class", "urn:content-classes:calendarmessage");
/* Most important part is to create alternate views:
You need to create two alternate views. One for calendar (mandatory) and another one for the mail body. (optional)
I highly recommend creating both views even if second one is optional.
If you don't create a separate alternate view for mail body, it will be simple text with no HTML whatsoever. So it will be a straight line. Users are not going to like that.
Mail body alternate view will allow the body to be sent as html.
*/
//Calendar Alternate View (mandatory)
StringBuilder str = new StringBuilder();
str.AppendLine("BEGIN:VCALENDAR");
str.AppendLine("PRODID:-//Schedule a Meeting");//no need to change to SharePoint ID
str.AppendLine("VERSION:2.0");
str.AppendLine("METHOD:REQUEST");
str.AppendLine("BEGIN:VEVENT");
str.AppendLine("CLASS:PUBLIC");
/*All date time objects should be in UTC format else the meeting invite will break.
Most probably this is an Outlook meeting requirement
eventStartTime and eventEndTime objects are converted into UTC format.
You may ask how to do it, so here is an example:
eventStartTime = DateTimeOffset.Parse(currentItem[Constants.EventsListFieldStartTime].ToString()).UtcDateTime;
*/
str.AppendLine(string.Format("CREATED:{0:yyyyMMddTHHmmss}", DateTime.Now));
str.AppendLine(string.Format("DTSTART:{0:yyyyMMddTHHmmssZ}", eventStartTime));
str.AppendLine(string.Format("DTSTAMP:{0:yyyyMMddTHHmmssZ}", DateTime.UtcNow));
str.AppendLine(string.Format("DTEND:{0:yyyyMMddTHHmmssZ}", eventEndTime));
str.AppendLine(string.Format("LOCATION:{0}", eventLocation));
str.AppendLine(string.Format("UID:{0}", Guid.NewGuid().ToString()));
str.AppendLine(string.Format("DESCRIPTION:{0}", msg.Body));
str.AppendLine(string.Format("X-ALT-DESC;FMTTYPE=text/html:{0}", msg.Body));
str.AppendLine(string.Format("SUMMARY;LANGUAGE=en-us: Scheduled for {0}", msg.Subject));
str.AppendLine(string.Format("ORGANIZER:MAILTO:{0}", msg.From.Address));
/*
Below is how we create meeting alert for user.
TRIGGER:-PT15M
It means that user alert will activate 15 minutes before the meeting starting time.
You can change it based on your requirements
*/
str.AppendLine("BEGIN:VALARM");
str.AppendLine("TRIGGER:-PT15M");
str.AppendLine("ACTION:DISPLAY");
str.AppendLine("DESCRIPTION:Reminder");
str.AppendLine("END:VALARM");
str.AppendLine("END:VEVENT");
str.AppendLine("END:VCALENDAR");
string eventsHomeUrl = SPContext.Current.Site.Url + Constants.EventsWebUrl;
SmtpClient smtpclient = new SmtpClient(GetSMTPHostName(eventsHomeUrl));
smtpclient.Credentials = CredentialCache.DefaultNetworkCredentials;
//add mail body HTML type alternate view
ContentType HtmlCtype = new ContentType("text/html");
//eventPresenter and eventDescription are event item column values
string bodyHtml = GetBodyHtml(eventPresenter + "<br>" + eventDescription);
AlternateView HtmlView = AlternateView.CreateAlternateViewFromString(bodyHtml, HtmlCtype);
msg.AlternateViews.Add(HtmlView);
//REMEMBER to add Calendar view last / all other views before it else Outlook invite won't work
ContentType contype = new ContentType("text/calendar");
contype.Parameters.Add("method", "REQUEST");
AlternateView avCal = AlternateView.CreateAlternateViewFromString(str.ToString(), contype);
msg.AlternateViews.Add(avCal);
smtpclient.Send(msg);
}
/*
Get SMTP host name from SharePoint outgoing e-mail settings. Good practice to set it at web application level.
*/
private static string GetSMTPHostName(string siteUrl)
{
using (SPSite site = new SPSite(siteUrl))
{
//Get the SMTP host name from “Outgoing e-mail settings”
return site.WebApplication.OutboundMailServiceInstance.Parent.Name;
}
}
/*
Last but not least is how to create mail body. It is self explanatory. See below:
*/
private static string GetBodyHtml(string body)
{
string bodyHtml =
@"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 3.2//EN"">"
+ @"<HTML>"
+ @"<HEAD>"
+ @"<META HTTP-EQUIV=""Content-Type"" CONTENT=""text/html; charset=utf-8"">"
+ @"<META NAME=""Generator"" CONTENT=""MS Exchange Server version 6.5.7652.24"">"
//+ @"<TITLE>{0}</TITLE>"
+ @"</HEAD>"
+ @"<BODY>"
+ @"<BR>"
+ @"{0}"
+ @"</BODY>"
+ @"</HTML>";
return String.Format(bodyHtml, body);
}
Do comment if this blog has helped you!