Outlook: Reply to HTML emails with plain text

Update: Alex remembered the add-in I ment: QuoteFix. Due to incompatibility issues with nowadays Outlook versions the guys published a VBA script doing mostly the same as the older add-in. Alex did some fine tuning on their script and applied parts of my snippet. Try his gist to get the best of both (mine and QuoteFix). Works like a charm for me.

When using Outlook to send/receive emails you usually press the reply (or reply all, forward) button to send back an answer. This works like a charm if the email you want to reply to was sent in plain text and you have the "line indention with prefix" option enabled in the Outlook settings.


Thus commenting the received email is pretty easy. Obviously there is no option to configure Outlook to reply to a HTML/RichText message with a plain text email too. So replying to such formatted mails with the "line indention with prefix" option enabled looks like this:


If you now try to write inline comments it is IMHO really hard for the recipient to find those in your reply. One might say: you can convert the reply message to plain text. Yes you can! But this won't convert the silly blue line into '>' prefixes. So I was looking for an add-in to solve this problem. I thought there was one I used in earlier Outlook versions, but couldn't find it anymore. After boongleing for an hour I decided to implement this using VBA. This is the result:

Enum AnswerType
    Forward = 0
    Reply = 1
    ReplyAll = 3
End Enum

Function DisplayPlainTextMessage(msg As MailItem, addPrefix As Boolean)
  Dim prefix As String
  If addPrefix = True Then prefix = "> "
  msg.BodyFormat = olFormatPlain
  Dim lines() As String
  lines = Strings.Split(msg.body, vbCrLf)
  Dim newBody As String
  For i = 0 To UBound(lines)
    If Trim(lines(i)) = "--" Then GoTo Break
    newBody = newBody & prefix & Trim(lines(i)) & vbCrLf
  msg.body = newBody
End Function

Function SendAsPlainText(how As AnswerType)
  On Error GoTo ErrorHandler

  Dim msg As Outlook.MailItem
  Set msg = GetMailItem

  If msg Is Nothing Then
    MsgBox ("No message selected.")
    GoTo ProgramExit
  End If
  Select Case how
    Case AnswerType.Forward
      Call DisplayPlainTextMessage(msg.Forward, msg.BodyFormat <> olFormatPlain)
    Case AnswerType.Reply
      Call DisplayPlainTextMessage(msg.Reply, msg.BodyFormat <> olFormatPlain)
    Case AnswerType.ReplyAll
      Call DisplayPlainTextMessage(msg.ReplyAll, msg.BodyFormat <> olFormatPlain)
  End Select

  Exit Function
  MsgBox Err.Number & " - " & Err.Description
  Resume ProgramExit
End Function

Sub ForwardAsPlainText()
  Call SendAsPlainText(AnswerType.Forward)
End Sub

Sub ReplyAsPlainText()
  Call SendAsPlainText(AnswerType.Reply)
End Sub

Sub ReplyAllAsPlainText()
  Call SendAsPlainText(AnswerType.ReplyAll)
End Sub

Function GetMailItem() As Outlook.MailItem

  On Error Resume Next

  Select Case TypeName(Application.ActiveWindow)
    Case "Explorer"

      If TypeName(ActiveExplorer.Selection.Item(1)) = "MailItem" Then
        Set GetMailItem = ActiveExplorer.Selection.Item(1)
      End If

    Case "Inspector"

      If TypeName(ActiveInspector.CurrentItem) = "MailItem" Then
        Set GetMailItem = ActiveInspector.CurrentItem
      End If
  End Select
  On Error GoTo 0
End Function

You can now modify your ribbon bar to add new buttons to the three subs ReplyAsPlainText, ReplyAllAsPlainText, ForwardAsPlainText:


Release of Silverlight Whiteboard


After a long run on a bumpy road our Trian.Whiteboard finally found it's way to the MSDN Code Gallery. Even if Microsoft Silverlight 3 is knocking on our doors this smart sample is a good start to get in touch with this technology. It shows how to use XAML to create a Rich Internet Application that communicates with a Windows Communication Foundation service in the background.

Check it out: http://code.msdn.microsoft.com/whiteboard
Play with it: http://playground.pixelplastic.de

.NET Bootcamp zu Silverlight und WPF

Am 20. März 2009 wird unter meiner Regie das dritte .NET Bootcamp der .NET User Group Leipzig stattfinden. Wie sollte es anders sein, geht es dabei um Microsoft Silverlight und die WPF. Die Registrierung ist ab heute aktiviert. Die Plätze sind limitiert, daher schnell anmelden. Falls ihr nicht wisst, was hinter den Bootcamps steckt und wie diese ablaufen, kann ich diesen Artikel von Torsten empfehlen.


Commenting your source is recommended and pretty helpful. But while implementing (e.g. SharpTM) most time it is annoying to scroll through all the big comment blocks. To get an overview of all class members it would be great to have the opportunity to collapse all comment blocks above all methods, properties, etc. That's why I tried to find a macro to do this - without success. So I wrote it by my own based on a region collapse macro I found here. And this is the modified function to do the job:

Public IsSummaryCommentsOutlineCollapsed As Dictionary(Of Document, Boolean) '' '' Toggling all <summary> comment blocks from collapsed to expanded outline. '' Please add [Imports System.Collections.Generic] on top of this module. '' Sub ToggleSummaryCommentsOutlineExpansion() If (DTE.ActiveDocument Is Nothing) Then Exit Sub End If If (DTE.UndoContext.IsOpen) Then DTE.UndoContext.Close() End If DTE.SuppressUI = True Try DTE.UndoContext.Open("ToggleSummaryCommentsOutline") Catch End Try If (IsSummaryCommentsOutlineCollapsed Is Nothing) Then IsSummaryCommentsOutlineCollapsed = New Dictionary(Of Document, Boolean) End If If (Not IsSummaryCommentsOutlineCollapsed.ContainsKey(DTE.ActiveDocument)) Then IsSummaryCommentsOutlineCollapsed.Add(DTE.ActiveDocument, False) End If Dim objSelection As TextSelection = DTE.ActiveDocument.Selection Dim line As Integer = objSelection.CurrentLine objSelection.StartOfDocument() ' find all <summary> blocks While objSelection.FindText("^:b*///:b*\<summary\>.*$", vsFindOptions.vsFindOptionsRegularExpression Or vsFindOptions.vsFindOptionsMatchInHiddenText) If (Not IsSummaryCommentsOutlineCollapsed.Item(DTE.ActiveDocument)) Then DTE.ExecuteCommand("Edit.ToggleOutliningExpansion") End If End While IsSummaryCommentsOutlineCollapsed.Item(DTE.ActiveDocument) = Not IsSummaryCommentsOutlineCollapsed.Item(DTE.ActiveDocument) objSelection.StartOfDocument() objSelection.GotoLine(line) DTE.UndoContext.Close() DTE.SuppressUI = False End Sub

In addition I just assigned a shortcut (Ctrl-M, C) to this macro to provide quick access while editing my sources.

Assign shortcut to Visual Studio macro

Update: Due to a comment of Torsten to add an undo option I implemented the support for toggling between collapsed and expanded mode and the undo functionality. Now running the ToggleSummaryCommentsOutlineExpansion function will collapse the first time for each document and toggles between expanded and collapsed mode each time you trigger this method.

For a long time I was looking for an elegant way to present my tons of pictures to friends and visitors of my blog. I played around with Silverlight to implement my own picture viewer, but wasn't happy with all my attempts. Last week I gave Deep Zoom a chance and now think that I found the right solution for my problem. You may have seen those fancy samples about the Deep Zoom technology like the Hard Rock Memorabilia. If you just don't know what Deep Zoom is I can recommend this presentation of Blaise Aguera y Arcas at TED.

Deep Zoom Composer - compose modeDeep Zoom Composer is a nice and handy tool to generate the tile patterns for each zoom level of a big image collection and to build up the so called sparse image scene graph with visual support. This graph contains the layout information (origin and scaling) of each image that is part of a Deep Zoom scene. Running the export process (3rd and last step) an XML file named SparseImageSceneGraph.xml will be produced. This is the source for the sparse image generation process that will create the tiles tree containing all the small image assets and an Deep Zoom Collection XML file (dzc_output.xml). The dzc_output.xml file in turn can be interpreted by a Silverlight application using the MultiScaleImage element to get access to all image tiles in the tree structure. That's the way Deep Zoom Composer works.

The problem and its solution

This process has a small problem for me. Looking at the large amount of pictures I've shoot since 2001 (around 30.000) it would be a hassle to manually arrange those (collection by collection) using the Deep Zoom Composer, where you have to drag & drop and scale each image on the surface. Okay there is the "Arrange in a Grid" feature that (in my opinion) does not result in a very eye-catching layout. That's why I came to the conclusion of writing a small .NET console application that will manage this issue for me in an automatic way. SparseImageSceneGenerator was born.

Compared to the process of Deep Zoom Composer this tool will help you to automate the composing process to generate the SparseImageSceneGraph.xml. The command line application only needs at least two arguments: a path to the location of your images and an output path to the resulting SparseImageSceneGraph.xml file. SparseImageSceneGenerator reads and analysis the properties of all images to create a nearly square shaped layout for all images. Before going into detail here is the result:

How it works in detail


(1) After reading all properties (size and metadata) of all pictures the sum and the square root of this sum for all aspect ratios will be calculated.


(2) The square root now limits the width of a rectangle where each image will be aligned row by row (including a cell padding between each image). In the figure above the sum of the aspect ratios of the two portrait images results in 1.333 (plus padding). The 3rd landscape image (AR = 1.5) does not fit into the row, because it will overflow the limit of 1.87 (plus padding). So it wraps to the next row. This generated grid now contains the final layout of all images.


(3) In a final step we have to adjust each rows width to be 1.0. This means scaling the width and origin of each image and row. That's it.

As you can see in the above sample the result is not a perfect square. It depends on the number of images. The more, the better (as you can see in the sample above). In addition SparseImageSceneGenerator supports the SparseImageTool that is part of the DZC installation to merge smoothly into the whole generation process. SparseImageTool is the command line version of the export process of DZC to create the final result based on the SparseImageSceneGraph.xml. The result is (as we know from the DZC export process) the dzc_output.xml file and the tree of tiles.


Feel free to download the current version and please give me feedback on this tool:

After Microsoft released the final version of Silverlight 2.0 last week I decided to update some of my samples I published before. Converting the Silverlight 2.0 Beta 2 based samples (physics attractor and the bending bezier curve) was straight forward without any problems. Instead the Silverlight 2.0 alpha based clock sample made some more work. That's why I decided to setup a new solution and start from scratch by rewriting the code behind files.

Feel free to download the source files:


Zwei wundervolle Tage - .NET Open Space in Leipzig

Gerade sind wir (Alex und ich) wieder daheim angekommen und haben die letzten Kisten mit all den Resten der letzten beiden Tage irgendwo in unserer WG untergebracht. Lecker Kuchen von der Bäckerei Göbecke stehen auch noch in Hülle und Fülle auf dem Küchentisch. Neben dem vielen ausnahmslos positivem Feedback der Teilnehmer haben die Organisatoren Torsten, Stefan, Alex (und ich irgendwie) mit dauerhaftem Grinsen den Mediencampus Villa Ida in Leipzig verlassen. Es war ein anstrengendes jedoch sehr gewinnbringendes Wochenende - für alle.


Ich selbst war anfangs skeptisch, ob wir, die Teilnehmer, es schaffen die Veranstaltung so zu gestalten und zu beleben wie vorgesehen. Also dass sich alle am Geschehen beteiligen, die Beiträge spontan durch die Teilnehmer erstellt werden und der .NET Open Space zu dem wurde, was er werden sollte.

Solch eine "Unkonferenz" wie sie hier organisiert wurde füllt für mich (und alle anderen) genau diese Lücken, die auf gewöhnlichen Konferenzen entstehen. Die fehlende Kommunikation mit und unter den Teilnehmern wurde auf dem .NET Open Space durch das zugrunde liegende Konzept ausgebügelt.

Ein dickes Dankeschön an alle Teilnehmer, Sponsoren und vor allem den helfenden Händen (Antje, Jule, Katrin, Steffi, Susi, Maik der Hausmeister, Matthias und Yvonne), die dieses Ereignis ermöglicht haben. Ich hoffe wir sehen uns alle spätestens nächstes Jahr wieder - zum .NET Open Space 2009.

3x Thumbs up. Ein echt cooles Wochenende.


Very simple Silverlight physics demo

This is the result of a 3h implementation of a simple physical sample. Each dot is attracted by the mouse cursor. So just move your mouse over the field to see the effect. The sources of this very small sample can be downloaded here.

Usability Thementag am 18. April in Leipzig

Benutzerfreundlichkeit ist zunehmend ein wichtiger Bestandteil heutiger Softwareentwicklungsprozesse. Sowohl für Desktop-Anwendungen als auch im Bereich des Web ist es notwendig den Endbenutzern eine intuitive Oberfläche zur Verfügung zu stellen, um effektiv und benutzerfreundlich mit dem Produkt arbeiten zu können. Dies spiegelt sich in einer höheren Produktivität beim Umgang mit der Anwendung wieder.

imageNeben technologieorientierten Lösungsansätzen, wird im ersten von drei Vorträgen im Allgemeinen auf Benutzerfreundlichkeit im alltäglichen Leben eingegangen. Weiter geht es mit Usability-Aspekten im Bereich des Web, gefolgt von einem Vortrag zu technischen Möglichkeiten mit der Windows Presentation Foundation (WPF) und Silverlight. Abgerundet wird dieser Tag mit einem 90minütigen Workshop, wo die gelernten WPF-Kenntnisse in einer kleinen Demo-Anwendung direkt am Rechner umgesetzt werden können.

Die Anmeldung erfolgt über eine E-Mail an anmeldung AT dotnet-leipzig DOT de mit Vorname, Nachnahme und dem Betreff "Usability". Die Teilnehmerzahl ist bzgl. des Workshops begrenzt. Gibt es mehr Anmeldungen als Plätze, entscheidet die Warteliste.

18.04.2008, 9:00 – 17:00 Uhr, Universität Leipzig (WiFa), Marschnerstraße 31, Raum 240.

Student Technology Conference 2008


location02Am 15. Mai 2008 ist es wieder soweit. Die alljährliche Konferenz für Studenten wird diesmal leider nur an einem Tag in Berlin stattfinden. Dafür aber kostenlos, wie ich dem Registrierungsformular entnehmen konnte. Die Teilnehmer können wie immer interessante Vorträge für IT Pros und .NET Entwickler erwarten.  Auch die angekündigte Location "Kalkscheune" macht einen netten Eindruck. Weitere Infos findet ihr unter www.studentconference.de.