Tuesday, October 23, 2007

Send Outlook Meeting Requests with System.Net.Mail

Here's a class I developed to send Outlook Meeting Requests via SMTP Email using the System.Net.Mail library. Just instantiate the AppointmentBLL object, passing in the desired parameters for the meeting, then call EmailAppointment to actually send it.

This ended up being more difficult than I anticipated. You have to create a "multipart/alternative" message, and the calendar item is in VCALENDAR format. After some fiddling with the header parameters and VCALENDAR file, I finally got it to work, and that was after wasting a bunch of time with CDOSYS and MAPI. Enjoy...



Imports Microsoft.VisualBasic
Imports System.Net.Mail

Public Class AppointmentBLL
' This class formats and sends a meeting request via SMTP email

Public StartDate As DateTime
Public EndDate As DateTime
Public Subject As String
Public Summary As String
Public Location As String
Public AttendeeName As String
Public AttendeeEmail As String
Public OrganizerName As String
Public OrganizerEmail As String

Public Sub New(ByVal pdtStartDate As DateTime, _
ByVal pdtEndDate As DateTime, _
ByVal psSubject As String, _
ByVal psSummary As String, _
ByVal psLocation As String, _
ByVal psAttendeeName As String, _
ByVal psAttendeeEmail As String, _
ByVal psOrganizerName As String, _
ByVal psOrganizerEmail As String)

' Copy constructor parameters to public propeties

StartDate = pdtStartDate
EndDate = pdtEndDate
Subject = psSubject
Summary = psSummary
Location = psLocation
AttendeeName = psAttendeeName
AttendeeEmail = psAttendeeEmail
OrganizerName = psOrganizerName
OrganizerEmail = psOrganizerEmail
End Sub


Public Sub EmailAppointment()

' Send the calendar message to the attendee

Dim loMsg As New MailMessage
Dim loTextView As AlternateView = Nothing
Dim loHTMLView As AlternateView = Nothing
Dim loCalendarView As AlternateView = Nothing
Dim loSMTPServer As New SmtpClient

' SMTP settings set up in web.config such as:
' <system.net>
' <mailSettings>
' <smtp>
' <network
' host = "exchange.mycompany.com"
' port = "25"
' userName = "username"
' password="password" />
' </smtp>
' </mailSettings>
' </system.net>

' Set up the different mime types contained in the message
Dim loTextType As System.Net.Mime.ContentType = New System.Net.Mime.ContentType("text/plain")
Dim loHTMLType As System.Net.Mime.ContentType = New System.Net.Mime.ContentType("text/html")
Dim loCalendarType As System.Net.Mime.ContentType = New System.Net.Mime.ContentType("text/calendar")

' Add parameters to the calendar header
loCalendarType.Parameters.Add("method", "REQUEST")
loCalendarType.Parameters.Add("name", "meeting.ics")

' Create message body parts
loTextView = AlternateView.CreateAlternateViewFromString(BodyText(), loTextType)
loMsg.AlternateViews.Add(loTextView)

loHTMLView = AlternateView.CreateAlternateViewFromString(BodyHTML(), loHTMLType)
loMsg.AlternateViews.Add(loHTMLView)

loCalendarView = AlternateView.CreateAlternateViewFromString(VCalendar(), loCalendarType)
loCalendarView.TransferEncoding = Net.Mime.TransferEncoding.SevenBit
loMsg.AlternateViews.Add(loCalendarView)

' Adress the message

loMsg.From = New MailAddress(OrganizerEmail)
loMsg.To.Add(New MailAddress(AttendeeEmail))
loMsg.Subject = Subject

' Send the message
loSMTPServer.DeliveryMethod = SmtpDeliveryMethod.Network
loSMTPServer.Send(loMsg)
End Sub

Public Function BodyText() As String

' Return the Body in text format

Const BODY_TEXT = _
"Type:Single Meeting" & vbCrLf & _
"Organizer: {0}" & vbCrLf & _
"Start Time:{1}" & vbCrLf & _
"End Time:{2}" & vbCrLf & _
"Time Zone:{3}" & vbCrLf & _
"Location: {4}" & vbCrLf & _
vbCrLf & _
"*~*~*~*~*~*~*~*~*~*" & vbCrLf & _
vbCrLf & _
"{5}"

Return String.Format(BODY_TEXT, _
OrganizerName, _
StartDate.ToLongDateString & " " & StartDate.ToLongTimeString, _
EndDate.ToLongDateString & " " & EndDate.ToLongTimeString, _
System.TimeZone.CurrentTimeZone.StandardName, _
Location, _
Summary)

End Function

Public Function BodyHTML() As String

' Return the Body in HTML format

Const BODY_HTML = _
"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 3.2//EN"">" & vbCrLf & _
"<HTML>" & vbCrLf & _
"<HEAD>" & vbCrLf & _
"<META HTTP-EQUIV=""Content-Type"" CONTENT=""text/html; charset=utf-8"">" & vbCrLf & _
"<META NAME=""Generator"" CONTENT=""MS Exchange Server version 6.5.7652.24"">" & vbCrLf & _
"<TITLE>{0}</TITLE>" & vbCrLf & _
"</HEAD>" & vbCrLf & _
"<BODY>" & vbCrLf & _
"<!-- Converted from text/plain format -->" & vbCrLf & _
"<P><FONT SIZE=2>Type:Single Meeting<BR>" & vbCrLf & _
"Organizer:{1}<BR>" & vbCrLf & _
"Start Time:{2}<BR>" & vbCrLf & _
"End Time:{3}<BR>" & vbCrLf & _
"Time Zone:{4}<BR>" & vbCrLf & _
"Location:{5}<BR>" & vbCrLf & _
"<BR>" & vbCrLf & _
"*~*~*~*~*~*~*~*~*~*<BR>" & vbCrLf & _
"<BR>" & vbCrLf & _
"{6}<BR>" & vbCrLf & _
"</FONT>" & vbCrLf & _
"</P>" & vbCrLf & _
vbCrLf & _
"</BODY>" & vbCrLf & _
"</HTML>"

Return String.Format(BODY_HTML, _
Summary, _
OrganizerName, _
StartDate.ToLongDateString & " " & StartDate.ToLongTimeString, _
EndDate.ToLongDateString & " " & EndDate.ToLongTimeString, _
System.TimeZone.CurrentTimeZone.StandardName, _
Location, _
Summary)

End Function

Public Function VCalendar() As String

' Return the Calendar text in vCalendar format, compatible with most calendar programs

Const lcDateFormat = "yyyyMMddTHHmmssZ"
Dim loGUID As Guid = Guid.NewGuid ' Or use the guid of an exiting meeting?

Const VCAL_FILE = "BEGIN:VCALENDAR" & vbCrLf & _
"METHOD:REQUEST" & vbCrLf & _
"PRODID:Microsoft CDO for Microsoft Exchange" & vbCrLf & _
"VERSION:2.0" & vbCrLf & _
"BEGIN:VTIMEZONE" & vbCrLf & _
"TZID:(GMT-06.00) Central Time (US & Canada)" & vbCrLf & _
"X-MICROSOFT-CDO-TZID:11" & vbCrLf & _
"BEGIN:STANDARD" & vbCrLf & _
"DTSTART:16010101T020000" & vbCrLf & _
"TZOFFSETFROM:-0500" & vbCrLf & _
"TZOFFSETTO:-0600" & vbCrLf & _
"RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=11;BYDAY=1SU" & vbCrLf & _
"END:STANDARD" & vbCrLf & _
"BEGIN:DAYLIGHT" & vbCrLf & _
"DTSTART:16010101T020000" & vbCrLf & _
"TZOFFSETFROM:-0600" & vbCrLf & _
"TZOFFSETTO:-0500" & vbCrLf & _
"RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=2SU" & vbCrLf & _
"END:DAYLIGHT" & vbCrLf & _
"END:VTIMEZONE" & vbCrLf & _
"BEGIN:VEVENT" & vbCrLf & _
"DTSTAMP:{8}" & vbCrLf & _
"DTSTART:{0}" & vbCrLf & _
"SUMMARY:{7}" & vbCrLf & _
"UID:{5}" & vbCrLf & _
"ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=""{9}"":MAILTO:{9}" & vbCrLf & _
"ACTION;RSVP=TRUE;CN=""{4}"":MAILTO:{4}" & vbCrLf & _
"ORGANIZER;CN=""{3}"":mailto:{4}" & vbCrLf & _
"LOCATION:{2}" & vbCrLf & _
"DTEND:{1}" & vbCrLf & _
"DESCRIPTION:{7}\N" & vbCrLf & _
"SEQUENCE:1" & vbCrLf & _
"PRIORITY:5" & vbCrLf & _
"CLASS:" & vbCrLf & _
"CREATED:{8}" & vbCrLf & _
"LAST-MODIFIED:{8}" & vbCrLf & _
"STATUS:CONFIRMED" & vbCrLf & _
"TRANSP:OPAQUE" & vbCrLf & _
"X-MICROSOFT-CDO-BUSYSTATUS:BUSY" & vbCrLf & _
"X-MICROSOFT-CDO-INSTTYPE:0" & vbCrLf & _
"X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY" & vbCrLf & _
"X-MICROSOFT-CDO-ALLDAYEVENT:FALSE" & vbCrLf & _
"X-MICROSOFT-CDO-IMPORTANCE:1" & vbCrLf & _
"X-MICROSOFT-CDO-OWNERAPPTID:-1" & vbCrLf & _
"X-MICROSOFT-CDO-ATTENDEE-CRITICAL-CHANGE:{8}" & vbCrLf & _
"X-MICROSOFT-CDO-OWNER-CRITICAL-CHANGE:{8}" & vbCrLf & _
"BEGIN:VALARM" & vbCrLf & _
"ACTION:DISPLAY" & vbCrLf & _
"DESCRIPTION:REMINDER" & vbCrLf & _
"TRIGGER;RELATED=START:-PT00H15M00S" & vbCrLf & _
"END:VALARM" & vbCrLf & _
"END:VEVENT" & vbCrLf & _
"END:VCALENDAR" & vbCrLf

Return String.Format(VCAL_FILE, _
StartDate.ToUniversalTime().ToString(lcDateFormat), _
EndDate.ToUniversalTime().ToString(lcDateFormat), _
Location, _
OrganizerName, _
OrganizerEmail, _
"{" & loGUID.ToString() & "}", _
Summary, _
Subject, _
Now.ToUniversalTime().ToString(lcDateFormat), _
AttendeeEmail)
End Function

End Class

Tuesday, October 2, 2007

Drop-in ASP.NET code for US State List

I often need a dropdownlist of US States. It's a pain to create it from scratch, so here's one I put together. I hope you find this useful...


<asp:DropDownList ID="ddlState" runat="server">
<asp:ListItem Value="">Choose State</asp:ListItem>
<asp:ListItem Value="AL">Alabama</asp:ListItem>
<asp:ListItem Value="AK">Alaska</asp:ListItem>
<asp:ListItem Value="AZ">Arizona</asp:ListItem>
<asp:ListItem Value="AR">Arkansas</asp:ListItem>
<asp:ListItem Value="CA">Califonia</asp:ListItem>
<asp:ListItem Value="CO">Colorado</asp:ListItem>
<asp:ListItem Value="CT">Connecticut</asp:ListItem>
<asp:ListItem Value="DE">Delaware</asp:ListItem>
<asp:ListItem Value="DC">Washington DC</asp:ListItem>
<asp:ListItem Value="FL">Florida</asp:ListItem>
<asp:ListItem Value="GA">Georgia</asp:ListItem>
<asp:ListItem Value="HI">Hawaii</asp:ListItem>
<asp:ListItem Value="ID">Idaho</asp:ListItem>
<asp:ListItem Value="IL">Illinois</asp:ListItem>
<asp:ListItem Value="IN">Indiana</asp:ListItem>
<asp:ListItem Value="IA">Iowa</asp:ListItem>
<asp:ListItem Value="KS">Kansas</asp:ListItem>
<asp:ListItem Value="KY">Kentucky</asp:ListItem>
<asp:ListItem Value="LA">Louisiana</asp:ListItem>
<asp:ListItem Value="ME">Maine</asp:ListItem>
<asp:ListItem Value="MD">Maryland</asp:ListItem>
<asp:ListItem Value="MA">Massachusetts</asp:ListItem>
<asp:ListItem Value="MI">Michigan</asp:ListItem>
<asp:ListItem Value="MN">Minnesota</asp:ListItem>
<asp:ListItem Value="MS">Mississippi</asp:ListItem>
<asp:ListItem Value="MO">Missouri</asp:ListItem>
<asp:ListItem Value="MT">Montana</asp:ListItem>
<asp:ListItem Value="NE">Nebraska</asp:ListItem>
<asp:ListItem Value="NV">Nevada</asp:ListItem>
<asp:ListItem Value="NH">New Hampshire</asp:ListItem>
<asp:ListItem Value="NJ">New Jersey</asp:ListItem>
<asp:ListItem Value="NM">New Mexico</asp:ListItem>
<asp:ListItem Value="NY">New York</asp:ListItem>
<asp:ListItem Value="NC">North Carolina</asp:ListItem>
<asp:ListItem Value="ND">North Dakota</asp:ListItem>
<asp:ListItem Value="OH">Ohio</asp:ListItem>
<asp:ListItem Value="OK">Oklahoma</asp:ListItem>
<asp:ListItem Value="OR">Oregon</asp:ListItem>
<asp:ListItem Value="PA">Pennsylvania</asp:ListItem>
<asp:ListItem Value="RI">Rhode Island</asp:ListItem>
<asp:ListItem Value="SC">South Carolina</asp:ListItem>
<asp:ListItem Value="SD">South Dakota</asp:ListItem>
<asp:ListItem Value="TN">Tennessee</asp:ListItem>
<asp:ListItem Value="TX">Texas</asp:ListItem>
<asp:ListItem Value="UT">Utah</asp:ListItem>
<asp:ListItem Value="VT">Vermont</asp:ListItem>
<asp:ListItem Value="VA">Virginia</asp:ListItem>
<asp:ListItem Value="WA">Washington</asp:ListItem>
<asp:ListItem Value="WV">West Virginia</asp:ListItem>
<asp:ListItem Value="WI">Wisconsin</asp:ListItem>
<asp:ListItem Value="WY">Wyoming</asp:ListItem>
</asp:DropDownList>

About Me

Principal Partner at NetPositive, Inc., St. Louis, MO.