Using X-ALT-DESC / Applying HTML to calendar invites in Outlook - c#

I'm a beginner in C# (and any networking code to be honest). I'm trying to send a calendar invite, that will be wired when you click a button on the company's website. This is a typical n-tier system, using asp.net/C# and SQL.
We used to simply generate an ics that the user would then have to know to open with Outlook, but I've since learned how to manually code a VCALENDAR so it shows up right away in Outlook nice and neat.
It's all been going fairly smoothly, but I would now like the body of the calendar invite to be able to accept HTML, to attach links in particular. I've experimented with AlternateViews, but it seems that the "X-ALT-DESC" attribute inside of VCALENDAR should do exactly what I want. However, try as I may Outlook ignores it and uses the description. There is clearly something I am missing.
(To clarify, everything works & compiles, except for the HTML alt description)
private Guid? CreateEmail()
{
Guid eventGuid = Guid.NewGuid();
MailMessage msg = new MailMessage();
msg.IsBodyHtml = true;
msg.From = new MailAddress("fromemail", "From Name");
msg.To.Add(toEmail);
msg.Subject = subject;
StringBuilder s = new StringBuilder();
s.AppendLine("BEGIN:VCALENDAR");
s.AppendLine("VERSION:2.0");
s.AppendLine("PRODID:-//My Product//Outlook MIMEDIR//EN");
s.AppendLine("METHOD:" + method); //In this case, "REQUEST"
s.AppendLine("STATUS:" + status.status); //"CONFIRMED"
s.AppendLine("BEGIN:VEVENT");
s.AppendLine("UID:" + eventGuid.ToString());
s.AppendLine("PRIORITY" + status.priority); //3
s.AppendLine("X-MICROSOFT-CDO-BUSYSTATUS:" + ShowAs.ToString()); //"BUSY"
s.AppendLine("SEQUENCE:" + UpdateNumber);//0
s.AppendLine("DTSTAMP:" + DateTime.Now.ToUniversalTime().ToString());
s.AppendLine("DTSTART:" + DateTimetoCalTime(startTime));
s.AppendLine("DTEND:" + DateTimetoCalTime(endTime));
s.AppendLine("SUMMARY:" + subject);
s.AppendLine("LOCATION: " + location);
s.AppendLine("DESCRIPTION: " + "Plain simple description"
string html_begin = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">" +
"\n<html>" +
"\n<head>" +
"\n<title></title>" +
"\n</head>" +
"\n<body>" +
"\n<!-- Converted from text/rtf format -->\n\n<P DIR=LTR><SPAN LANG=\"en-us\">" +
"\n<Font face=\"Times New Roman\"";
body = "I simply <b> want some bold </b> here 555";
string html_end = "</font></span></body>\n</html>";
string html_body = html_begin + body + html_end;
msg.Body = html_body;
s.AppendLine("X-ALT-DESC;FMTTYPE=text/html:" + html_body);
msg.Body = html_body;
s.AppendLine("X-ALT_DESC;FMTTYPE=text/html:" + html_body);
s.AppendLine("STATUS:" + status.status); //"CONFIRMED"
s.AppendLine("BEGIN:VALARM");
s.AppendLine("TRIGGER:-PT1440M");
s.AppendLine("ACTION:Accept");
s.AppendLine("DESCRIPTION:Reminder");
s.AppendLine("END:VALARM");
s.AppendLine("END:VEVENT");
s.AppendLine(string.Format("ATTENDEE;CN=\"{0}\";RSVP=TRUE:mailto:{1}", msg.To[0].DisplayName, msg.To[0].Address));
s.AppendLine("END:VCALENDAR");
System.Net.Mime.ContentType type = new System.Net.Mime.ContentType("text/calendar");
type.Parameters.Add("method", method);
type.Parameters.Add("name", "meeting.ics");
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(s.ToString(), type));
SMTP.send(msg);
return EventGuid;
Produces this body in outlook:
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 3.2//EN”>
<html>
<head>
<title></title>
</head>
<body>
<!-- Converted from text/rtf format -->
<P DIR=LTR><SPAN LANG=”en-us”>
<Font face=”Times New Roman”I simply <b> want some bold </b> here 555</font></span></body>
</html>
From testing:
If I leave Msg.body out, it just used the "DESCRIPTION".
If I make it equal the HTML, I get the above result.
Thank You!

You can have X-ALT-DESC on multiple lines, you just need to add a space on the beginning of each lines following it.
Lines of text SHOULD NOT be longer than 75 octets, excluding the line break. Long content lines SHOULD be split into a multiple line representations using a line "folding" technique. That is, a long line can be split between any two characters by inserting a CRLF immediately followed by a single linear white-space character (i.e., SPACE or HTAB). Any sequence of CRLF followed immediately by a single linear white-space character is ignored (i.e., removed) when processing the content type.
https://icalendar.org/iCalendar-RFC-5545/3-1-content-lines.html

I found that the HTML string must be all on one line. If the HTML is broken over multiple lines, that does not conform to Vcalendar encoding and the description is either rendered as a blank page or as plain text with all HTML tags visible.
I've seen others out there claiming that the DESCRIPTION tag must be used in front of "X-ALT-DESC;FMTTYPE=text/html:". This is totally WRONG and FALSE. If "DESCRIPTION" exists, it takes precedence, the "X-ALT-DESC;FMTTYPE=text/html:" line is completely ignored by Outlook and the plain text description is rendered. Therefore, "X-ALT-DESC;FMTTYPE=text/html:" must stand on it's own and be on it's own line.
Working example:
...
X-ALT-DESC;FMTTYPE=text/html:<html><body>Bing</body></html>
...
Wrong:
...
DESCRIPTION;X-ALT-DESC;FMTTYPE=text/html:<html><body>Bing</body></html>
...
Wrong again:
...
X-ALT-DESC;FMTTYPE=text/html:<html>
<body>
Bing
</body>
</html>
...

For those in the future:
The problem was the use of
.AppendLine.
Simply use
.Append

The ics file which i am loading is not created with proper spaces which is longer than 75 octets, if i am manually adding space and loading to Ical.net.Calendar it works fine. But i want to do the same through c# code like manipulating the calendar file before loading to avoid parsing errors.

For reference, here's an explanation from https://icalendar.org/
"The original iCalendar standard allowed only plain text as part of an event description. HTML markup, such as font attributes (bold, underline) and layout (div, table) was not allowed in the text description field. First seen in Microsoft Outlook, the X-ALT-DESC parameter provides a method to add HTML to an event description. "X-" fields are allowed for non-standard, experimental parameters. This field has become the method of choice when including HTML in a description. When using HTML, both fields must be included so that iCalendar readers that do not support the X-ALT-DESC field can still read the text version."

...and it looks like Outlook 2016 dropped support for this. Generating ics files with html description only is most of the time not an option as Thunderbird/Lightening in the past did not handle this leading to calendar invites with empty body.
https://answers.microsoft.com/en-us/msoffice/forum/msoffice_outlook/outlook-2016-ics-description-shows-no-html/08d06cba-bfe4-4757-a052-adab64ea75a2?page=1

Related

HTML email css stripped after replacing text

I have a html template that works when it is as is and sent to my Gmail. The css works and the positioning of elements is fine.
However, I when I load it into my application and do a replace string of certain text and resend it from my application, I noticed that in Gmail, not only is the css gone but all positioning is messed up.
This is my html email as is without replacing the text:
http://s000.tinyupload.com/?file_id=00874388724644178645
This is how I load the html and replace the text:
HtmlDocument document = new HtmlDocument();
document.Load(#message.Location);
content = document.DocumentNode.OuterHtml;
content = content.Replace("##" + innerItem + "##", line);
var eContent = new HtmlString(content);
I then proceed to sent the eContent string to my email via another function.
This is my html email after I replaced the text:
http://s000.tinyupload.com/?file_id=03908737686605061545
I am unsure of how else I can handle this email template properly.
I'm using the HTML Agility Pack to read the document in also.
EDIT:
The replaced email works with other email providers like the CPanel one but not Gmail
This might happen if you have any character Gmail doesn't support in styles (may it be inline or in tags). This can include characters like =,*,/,$,%,`, &, #, ^, {, }, [, ], (, ), ?, |, <, > more about that. Feel free to post your code for further help.

Is Lotus notes email client unable to render <br > tag?

I have a weird problem with Lotus Notes 8.5. In my project I am sending meeting invitation to the user. for that, I generate .ics file. Here is how i generate .ics file
var body = "Dear Raj, \n\n How are you? line break is not working \n\n how?";
using (TextWriter writer = File.CreateText("../test.ics"))
{
writer.WriteLine("BEGIN:VCALENDAR");
writer.WriteLine("PRODID:-//Microsoft Corporation//Outlook 11.0 MIMEDIR//EN");
writer.WriteLine("VERSION:2.0");
writer.WriteLine("METHOD:REQUEST");
writer.WriteLine("BEGIN:VEVENT");
writer.WriteLine("ATTENDEE;ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:participant#company.com");
writer.WriteLine("ORGANIZER;CN="Organizer":MAILTO:organizer#test.ccc");
writer.WriteLine("(DTSTART:20141231T010000Z");
writer.WriteLine("DTEND:20141231T010000Z");
writer.WriteLine("TRANSP:OPAQUE");
writer.WriteLine("SEQUENCE:0");
writer.WriteLine("UID:Company-interview-123");
writer.WriteLine("DTSTAMP:20141223T232322Z");
writer.WriteLine("SUMMARY:Interview Scheduled for Job");
writer.WriteLine("DESCRIPTION:{0}", body.Replace("\n","<br />"));
//Adding below property actually fixed the issue.
writer.WriteLine("X-ALT-DESC;FMTTYPE=text/html:{0}", body.Replace("\n","<br />"));
writer.WriteLine("LOCATION:Test Location");
writer.WriteLine("PRIORITY:5");
writer.WriteLine("X-MICROSOFT-CDO-IMPORTANCE:1");
writer.WriteLine("CLASS:PUBLIC");
writer.WriteLine("BEGIN:VALARM");
writer.WriteLine("TRIGGER:-PT15M");
writer.WriteLine("ACTION:DISPLAY");
writer.WriteLine("DESCRIPTION:Reminder");
writer.WriteLine("END:VALARM");
writer.WriteLine("END:VEVENT");
writer.WriteLine("END:VCALENDAR");
}
But Lotus email client is displaying the content as such.
its showing
Dear Raj, <br><br> How are you? line break is not working <br><br> how?
On all other email clients, my content is displaying as
Dear Raj,
How are you? line break is not working
how?
Am i missing something here?
Updated my .ics generation code to add X-ALT-DESC;FMTTYPE=text/html: to fix the issue
I just checked with a vcard that contains your Text in Lotus Notes 8.5 and IBM Notes 9, and it worked exactly as expected. BUT: It worked with your "original" Text without the replace. In the RFC2445 it states, that Line- Breaks have to be encoded as \n:
An intentional formatted text line break MUST only be included in a
"TEXT" property value by representing the line break with the
character sequence of BACKSLASH (US-ASCII decimal 92), followed by a
LATIN SMALL LETTER N (US-ASCII decimal 110) or a LATIN CAPITAL LETTER
N (US-ASCII decimal 78), that is "\n" or "\N".
That means: use
writer.WriteLine("DESCRIPTION:{0}", body);
instead of
writer.WriteLine("DESCRIPTION:{0}", body.Replace("\n","<br>"));
And your problem should be solved
The DESCRIPTION property is not meant to contain any rich text/html content but only plain text.
Lotus Notes may use some other property (X- property) to convey rich text description. Or it may use an ALTREP parameter on the DESCRIPTION, that point to another MIME bodypart in the invitation. See https://www.rfc-editor.org/rfc/rfc5545#section-3.2.1
So what you probably want to do is to send an invitation containing rich text from Lotus Notes to some external account, and then see what the MIME message that you receive looks like.

Read Text file and Email in Plain Text without affecting the original Text

I have a plain text file that I need to read in using C#, manipulate it a bit then I need to email it. That's easy enough, but it also has to stay in the same format as it's original state:
This is an excerpt from a sample file "mySample.txt":
*****************************NB!!!!**********************************
*Please view http://www.sdfsdf.comsdfsdfsdf . *
*********************************************************************
*** DO NOT DELETE or ALTER ANY OF THE FOLLOWING TEXT ***
Company X PTY.
Lorem Ipsum Office
Last Change - 01 February 2008
APPLICATION TO ESTABLISH A COMMUNITY WITHIN
THE RESTIN DISTRICT OF THE IPSUM.
===================================================================
1. COMMUNITY and ACTION
Give the name of the community. This is the name that will be
used in tables and lists associating the community with the name
district and community forum. The community names that are
delegated by Lorem are at the district level
The Action field specifies whether this is a 'N'ew application, an
'U'pdate or a 'R' removal.
1a. Complete community name:**{0}**
1b. Action - [N]ew, [U]pdate, or [R]emoval :**{1}**
As you can see I've got place holders {0} and {1} in the file which is to be replaced by an automated process.
In my C# I'm using a stream reader to read the entire file into a StringBuilder object then replacing the place holders using the StringBuilder.AppendFormat method.
The problem is when I add the text to a email message body and send it the format ends up looking different. It looks like a bunch of spaces or tabs get removed in the process.
private void Submit_Click(object sender, EventArgs e)
{
//create mail client
System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient();
System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage();
message.To.Add(ConfigurationManager.AppSettings["SubmitToEmail"]);
message.Bcc.Add("xyz#test.com");
message.Subject = "Test Subject";
message.BodyEncoding = Encoding.ASCII;
message.IsBodyHtml = false;
message.Body = _PopulateForm(_GatherInput());//calls method to read the file and replace values
client.Send(message);
//cleanup
client = null;
message.Dispose();
message = null;
}
Anyone have any ideas on how to keep the formatting in tact?
Thanks,
Jacques
The problem you've got is that you're sending plain text as HTML. It's natural that the layout gets changed because HTML is displayed differently than text. Plain text has new lines (\n), tabs (\t), etc., while HTML has line breaks (<BR>) and different layout methods.
If I were you, I would 1st start out by replacing new lines with <BR> (there should be a replace function x.Replace("\n", "<BR>");)
As for the text items that are centered, wrap them in <p style="text-align:center" }>, </p>.
The answer seems to have been with .net and the Mail message object. Instead of adding the content to the Body property, you have to create an alternateView object and add it to that. That solved my problem.
Regards,
Jacques

Plain text to HTML conversion in Outlook email

I am facing a situation to preserve the formatting of plain text email when displaying it as virtual plain text in C sharp. This is done during receiving in Outlook 2007 using VSTO.
The code below does not do the job, instead it converts the body into Times New Roman;Font Size 10 and displays it to the user.
string Text = "<html><body><p style=\"font-family:consolas;font-size:88%;\">" + mailItem.Body+ "</p></body></html>";
mailItem.HTMLBody = Text;
mailItem.HTMLBody = Regex.Replace(mailItem.HTMLBody, "(ASA[a-z][a-z][0-9][0-9])", "$&");
How can I rectify this problem?
EDIT:
Input:
ASAss87
ASAjj98
this is test input
Output:
ASAss87 ASAjj98 this is test input
EDIT 2:
Input:
ASAss87
ASAjj98
this is test input.
Output:
ASAss87
ASAjj98
this is test input.
*Moves one or two spaces forward. I am using tag.
Based on your feedback in the comments, try changing your first line to use Body instead of HTMLBody:
string Text = "<html><body><p style=\"font-family:consolas;font-size:88%;\">" + mailItem.Body+ "</p></body></html>";
Edit: Since the plain text contains line-breaks, maybe you should use a <pre> tag instead of a <p> tag, to prevent it from putting everything on one line.
string Text = "<html><body><pre style=\"font-family:consolas;font-size:88%;\">" + mailItem.Body+ "</pre></body></html>";
Edit2: Alternatively, you can replace all line-breaks with <br> tags.
string Text = "<html><body><p style=\"font-family:consolas;font-size:88%;\">" + mailItem.Body.Replace(Environment.NewLine,"<BR>") + "</p></body></html>";

Creating iCal Files in c#

I'm looking for a good method of generating an iCalendar file (*.ics) in c# (asp.net). I've found a couple resources, but one thing that has been lacking is their support for quoted-printable fields - fields that have carriage returns and line feeds.
For example, if the description field isn't encoded properly, only the first line will display and possibly corrupting the rest of the information in the *.ics file.
I'm looking for existing classes that can generate *.ics files and/or a class that can generate quoted-printable fields.
I use DDay.Ical, its good stuff.
Has the ability to open up an ical file and get its data in a nice object model. It says beta, but it works great for us.
Edit Nov 2016
This library has been deprecated, but was picked up and re-released as iCal.NET by another dev.
Notes about the release: rianjs.net/2016/07/dday-ical-is-now-ical-net
Source on GitHub: github.com/rianjs/ical.net
The easiest way I've found of doing this is to markup your HTML using microformats.
If you're looking to generate iCalendar files then you could use the hCalendar microformat then include a link such as 'Add to Calendar' that points to:
http://feeds.technorati.com/events/[ your page's full URL including the http:// ]
The Technorati page then parses your page, extracts the hCalendar info and sends the iCalendar file to the client.
I wrote a shim function to handle this. It's mostly compliant--the only hangup is that the first line is 74 characters instead of 75 (the 74 is to handle the space on subsequent lines)...
Private Function RFC2445TextField(ByVal LongText As String) As String
LongText = LongText.Replace("\", "\\")
LongText = LongText.Replace(";", "\;")
LongText = LongText.Replace(",", "\,")
Dim sBuilder As New StringBuilder
Dim charArray() As Char = LongText.ToCharArray
For i = 1 To charArray.Length
sBuilder.Append(charArray(i - 1))
If i Mod 74 = 0 Then sBuilder.Append(vbCrLf & " ")
Next
Return sBuilder.ToString
End Function
I use this for the summary and description on our ICS feed. Just feed the line with the field already prepended (e.g. LongText = "SUMMARY:Event Title"). As long as you set caching decently long, it's not too expensive of an operation.
iCal (ical 2.0) and quoted-printable don't go together.
Quoted-printable is used a lot in vCal (vCal 1.0) to represent non-printable characters, e.g. line-breaks (=0D=0A). The default vCal encoding is 7-bit, so sometimes you need to use quoted-printable to represent non-ASCII characters (you can override the default encoding, but the other vCal-compliant communicating party is not required to understand it.)
In iCal, special characters are represented using escapes, e.g. '\n'. The default encoding is UTF-8, all iCal-compliant parties must support it and that makes quoted-printable completely unnecessary in iCal 2.0 (and vCard 3.0, for that matter).
You may need to back your customer/stakeholder to clarify the requirements. There seems to be confusion between vCal and iCal.
I'm missing an example with custom time zones. So here a snippet that show how you can set a time zone in the ics (and send it to the browser in asp.net).
//set a couple of variables for demo purposes
DateTime IcsDateStart = DateTime.Now.AddDays(2);
DateTime IcsDateEnd = IcsDateStart.AddMinutes(90);
string IcsSummary = "ASP.Net demo snippet";
string IcsLocation = "Amsterdam (Netherlands)";
string IcsDescription = #"This snippes show you how to create a calendar item file (.ics) in ASP.NET.\nMay it be useful for you.";
string IcsFileName = "MyCalendarFile";
//create a new stringbuilder instance
StringBuilder sb = new StringBuilder();
//begin the calendar item
sb.AppendLine("BEGIN:VCALENDAR");
sb.AppendLine("VERSION:2.0");
sb.AppendLine("PRODID:stackoverflow.com");
sb.AppendLine("CALSCALE:GREGORIAN");
sb.AppendLine("METHOD:PUBLISH");
//create a custom time zone if needed, TZID to be used in the event itself
sb.AppendLine("BEGIN:VTIMEZONE");
sb.AppendLine("TZID:Europe/Amsterdam");
sb.AppendLine("BEGIN:STANDARD");
sb.AppendLine("TZOFFSETTO:+0100");
sb.AppendLine("TZOFFSETFROM:+0100");
sb.AppendLine("END:STANDARD");
sb.AppendLine("END:VTIMEZONE");
//add the event
sb.AppendLine("BEGIN:VEVENT");
//with a time zone specified
sb.AppendLine("DTSTART;TZID=Europe/Amsterdam:" + IcsDateStart.ToString("yyyyMMddTHHmm00"));
sb.AppendLine("DTEND;TZID=Europe/Amsterdam:" + IcsDateEnd.ToString("yyyyMMddTHHmm00"));
//or without a time zone
//sb.AppendLine("DTSTART:" + IcsDateStart.ToString("yyyyMMddTHHmm00"));
//sb.AppendLine("DTEND:" + IcsDateEnd.ToString("yyyyMMddTHHmm00"));
//contents of the calendar item
sb.AppendLine("SUMMARY:" + IcsSummary + "");
sb.AppendLine("LOCATION:" + IcsLocation + "");
sb.AppendLine("DESCRIPTION:" + IcsDescription + "");
sb.AppendLine("PRIORITY:3");
sb.AppendLine("END:VEVENT");
//close calendar item
sb.AppendLine("END:VCALENDAR");
//create a string from the stringbuilder
string CalendarItemAsString = sb.ToString();
//send the ics file to the browser
Response.ClearHeaders();
Response.Clear();
Response.Buffer = true;
Response.ContentType = "text/calendar";
Response.AddHeader("content-length", CalendarItemAsString.Length.ToString());
Response.AddHeader("content-disposition", "attachment; filename=\"" + IcsFileName + ".ics\"");
Response.Write(CalendarItemAsString);
Response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();
Check out http://www.codeproject.com/KB/vb/vcalendar.aspx
It doesn't handle the quoted-printable fields like you asked, but the rest of the code is there and can be modified.
According to RFC-2445, the comment and description fields are TEXT. The rules for a test field are:
[1] A single line in a TEXT field is not to exceed 75 octets.
[2] Wrapping is achieved by inserting a CRLF followed by whitespace.
[3] There are several characters that must be encoded including \ (reverse slash) ; (semicolon) , (comma) and newline. Using a \ (reverse slash) as a delimiter gives \ \; \, \n
Example: The following is an example of the property with formatted
line breaks in the property value:
DESCRIPTION:Meeting to provide technical review for "Phoenix"
design.\n Happy Face Conference Room. Phoenix design team
MUST attend this meeting.\n RSVP to team leader.
iCal can be complicated, so I recommend using a library. DDay is a good free solution. Last I checked it didn't have full support for recurring events, but other than that it looks really nice. Definitely test the calendars with several clients.
i know it is too late, but it may help others. in my case i wrote following text file with .ics extension
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Calendly//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
DTSTAMP:20170509T164109Z
UID:your id-11273661
DTSTART:20170509T190000Z
DTEND:20170509T191500Z
CLASS:PRIVATE
DESCRIPTION:Event Name: 15 Minute Meeting\nDate & Time: 03:00pm - 03:15pm (
Eastern Time - US & Canada) on Tuesday\, May 9\, 2017\n\nBest Phone Number
To Reach You :: xxxxxxxxx\n\nany "link": https://wwww.yahoo.com\n\n
SUMMARY:15 Minute Meeting
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
it worked for me.

Categories

Resources