[evolution] Mail formatter rewrite



commit 5b8340563c271fb684a88c6e5bb6dd3bfb629058
Author: Dan VrÃtil <dvratil redhat com>
Date:   Wed Jun 6 15:27:19 2012 +0200

    Mail formatter rewrite
    
    All mail-parsing and formatting code has been moved to em-format.
    Parsing is handeled by EMailParser class, formatting by EMailFormatter.
    Both classes have registry which hold extensions - simple classes
    that do actual parsing and formatting. Each supported mime-type
    has it's own parser and formatter extension class.

 composer/e-msg-composer.c                          |   63 +-
 data/webview.css                                   |    2 +-
 em-format/Makefile.am                              |  105 +-
 em-format/e-mail-extension-registry.c              |  294 ++
 em-format/e-mail-extension-registry.h              |  156 +
 em-format/e-mail-extension.c                       |   67 +
 em-format/e-mail-extension.h                       |   60 +
 em-format/e-mail-format-extensions.c               |  124 +
 em-format/e-mail-format-extensions.h               |   88 +
 em-format/e-mail-formatter-attachment-bar.c        |  154 +
 em-format/e-mail-formatter-attachment.c            |  403 +++
 em-format/e-mail-formatter-error.c                 |  160 ++
 em-format/e-mail-formatter-extension.c             |  189 ++
 em-format/e-mail-formatter-extension.h             |  106 +
 em-format/e-mail-formatter-headers.c               |  615 ++++
 em-format/e-mail-formatter-image.c                 |  191 ++
 em-format/e-mail-formatter-message-rfc822.c        |  276 ++
 em-format/e-mail-formatter-print-headers.c         |  258 ++
 em-format/e-mail-formatter-print.c                 |  266 ++
 em-format/e-mail-formatter-print.h                 |   63 +
 em-format/e-mail-formatter-quote-attachment.c      |  163 ++
 em-format/e-mail-formatter-quote-headers.c         |  162 ++
 em-format/e-mail-formatter-quote-message-rfc822.c  |  188 ++
 em-format/e-mail-formatter-quote-text-enriched.c   |  141 +
 em-format/e-mail-formatter-quote-text-html.c       |  143 +
 em-format/e-mail-formatter-quote-text-plain.c      |  162 ++
 em-format/e-mail-formatter-quote.c                 |  224 ++
 em-format/e-mail-formatter-quote.h                 |   79 +
 em-format/e-mail-formatter-secure-button.c         |  472 +++
 em-format/e-mail-formatter-source.c                |  178 ++
 em-format/e-mail-formatter-text-enriched.c         |  154 +
 em-format/e-mail-formatter-text-html.c             |  376 +++
 em-format/e-mail-formatter-text-plain.c            |  212 ++
 em-format/e-mail-formatter-utils.c                 |  434 +++
 em-format/e-mail-formatter-utils.h                 |   56 +
 em-format/e-mail-formatter.c                       | 1510 ++++++++++
 em-format/e-mail-formatter.h                       |  266 ++
 .../{em-inline-filter.c => e-mail-inline-filter.c} |   37 +-
 .../{em-inline-filter.h => e-mail-inline-filter.h} |   48 +-
 em-format/e-mail-parser-application-mbox.c         |  213 ++
 em-format/e-mail-parser-application-smime.c        |  199 ++
 em-format/e-mail-parser-attachment-bar.c           |  120 +
 em-format/e-mail-parser-extension.c                |  101 +
 em-format/e-mail-parser-extension.h                |   86 +
 em-format/e-mail-parser-headers.c                  |  112 +
 em-format/e-mail-parser-image.c                    |  147 +
 em-format/e-mail-parser-inlinepgp-encrypted.c      |  205 ++
 em-format/e-mail-parser-inlinepgp-signed.c         |  230 ++
 em-format/e-mail-parser-message-deliverystatus.c   |  116 +
 em-format/e-mail-parser-message-external.c         |  211 ++
 em-format/e-mail-parser-message-rfc822.c           |  174 ++
 em-format/e-mail-parser-message.c                  |  129 +
 em-format/e-mail-parser-multipart-alternative.c    |  191 ++
 em-format/e-mail-parser-multipart-appledouble.c    |  130 +
 em-format/e-mail-parser-multipart-digest.c         |  175 ++
 em-format/e-mail-parser-multipart-encrypted.c      |  220 ++
 em-format/e-mail-parser-multipart-mixed.c          |  158 +
 em-format/e-mail-parser-multipart-related.c        |  162 ++
 em-format/e-mail-parser-multipart-signed.c         |  252 ++
 em-format/e-mail-parser-secure-button.c            |  104 +
 em-format/e-mail-parser-source.c                   |  108 +
 em-format/e-mail-parser-text-enriched.c            |  128 +
 em-format/e-mail-parser-text-html.c                |  138 +
 em-format/e-mail-parser-text-plain.c               |  253 ++
 em-format/e-mail-parser.c                          |  693 +++++
 em-format/e-mail-parser.h                          |  114 +
 em-format/e-mail-part-attachment-bar.h             |   34 +
 em-format/e-mail-part-attachment.c                 |   30 +
 em-format/e-mail-part-attachment.h                 |   45 +
 em-format/e-mail-part-list.c                       |  130 +
 em-format/e-mail-part-list.h                       |   76 +
 em-format/e-mail-part-utils.c                      |  546 ++++
 em-format/e-mail-part-utils.h                      |   58 +
 em-format/e-mail-part.c                            |  196 ++
 em-format/e-mail-part.h                            |   98 +
 ...-stripsig-filter.c => e-mail-stripsig-filter.c} |   18 +-
 ...-stripsig-filter.h => e-mail-stripsig-filter.h} |   42 +-
 em-format/em-format-quote.c                        |  844 ------
 em-format/em-format-quote.h                        |   79 -
 em-format/em-format.c                              | 2676 -----------------
 em-format/em-format.h                              |  333 ---
 mail/Makefile.am                                   |   10 -
 mail/e-http-request.c                              |   67 +-
 mail/e-mail-attachment-bar.h                       |   79 -
 mail/e-mail-browser.c                              |    7 +-
 mail/e-mail-browser.h                              |    2 +-
 mail/e-mail-config-lookup-page.c                   |    2 +-
 mail/e-mail-display.c                              |  779 +++---
 mail/e-mail-display.h                              |   16 +-
 mail/e-mail-folder-pane.c                          |    1 -
 mail/e-mail-paned-view.h                           |    2 -
 mail/e-mail-printer.c                              |  160 +-
 mail/e-mail-printer.h                              |    8 +-
 mail/e-mail-reader-utils.c                         |  351 ++-
 mail/e-mail-reader-utils.h                         |   17 +-
 mail/e-mail-reader.c                               |  217 +-
 mail/e-mail-reader.h                               |    4 +
 mail/e-mail-request.c                              |  110 +-
 mail/em-composer-utils.c                           |   57 +-
 mail/em-composer-utils.h                           |    6 +-
 mail/em-format-hook.c                              |  286 --
 mail/em-format-hook.h                              |   90 -
 mail/em-format-html-display.c                      | 1080 -------
 mail/em-format-html-display.h                      |  117 -
 mail/em-format-html-print.c                        |  634 ----
 mail/em-format-html-print.h                        |   66 -
 mail/em-format-html.c                              | 3011 --------------------
 mail/em-format-html.h                              |  223 --
 mail/em-utils.c                                    |   75 +-
 mail/em-utils.h                                    |    4 +-
 modules/mail/e-mail-config-format-html.c           |    4 +-
 modules/mail/e-mail-shell-backend.c                |   73 +-
 modules/mail/e-mail-shell-content.h                |    1 -
 modules/mail/e-mail-shell-view-actions.c           |    2 +-
 modules/mail/em-mailer-prefs.c                     |    1 -
 widgets/misc/Makefile.am                           |    2 +
 .../misc/e-attachment-bar.c                        |  224 +-
 widgets/misc/e-attachment-bar.h                    |   79 +
 widgets/misc/e-attachment-button.c                 |    3 +-
 119 files changed, 16050 insertions(+), 10539 deletions(-)
---
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index ae50482..90ce610 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -40,11 +40,15 @@
 #include <libevolution-utils/e-alert-dialog.h>
 #include <e-util/e-dialog-utils.h>
 #include <e-util/e-util-private.h>
-#include <em-format/em-format.h>
-#include <em-format/em-format-quote.h>
 
 #include "e-composer-private.h"
 
+#include <em-format/e-mail-part.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-formatter-quote.h>
+
+#include <shell/e-shell.h>
+
 typedef struct _AsyncContext AsyncContext;
 
 struct _AsyncContext {
@@ -179,49 +183,50 @@ static gchar *
 emcu_part_to_html (CamelSession *session,
                    CamelMimePart *part,
                    gssize *len,
-                   EMFormat *source,
                    GCancellable *cancellable)
 {
-	EMFormatQuote *emfq;
 	CamelStreamMem *mem;
 	GByteArray *buf;
 	gchar *text;
-	EMFormatParserInfo p_info = { 0 };
-	EMFormatWriterInfo w_info = { 0 };
+	EMailParser *parser;
+	EMailFormatter *formatter;
+	EMailPartList *part_list;
 	GString *part_id;
+	EShell *shell;
+	GtkWindow *window;
+
+	shell = e_shell_get_default ();
+	window = e_shell_get_active_window (shell);
 
 	buf = g_byte_array_new ();
 	mem = (CamelStreamMem *) camel_stream_mem_new ();
 	camel_stream_mem_set_byte_array (mem, buf);
 
-	emfq = em_format_quote_new (
-		session, NULL, (CamelStream *) mem,
-		EM_FORMAT_QUOTE_KEEP_SIG);
-	em_format_set_composer ((EMFormat *) emfq, TRUE);
-	if (source) {
-		/* Copy over things we can, other things are internal.
-		 * XXX Perhaps need different api than 'clone'. */
-		if (em_format_get_default_charset (source))
-			em_format_set_default_charset (
-				(EMFormat *) emfq, em_format_get_default_charset (source));
-		if (em_format_get_charset (source))
-			em_format_set_charset (
-				(EMFormat *) emfq, em_format_get_charset (source));
-	}
+	part_list = e_mail_part_list_new ();
 
 	part_id = g_string_sized_new (0);
-	em_format_parse_part (EM_FORMAT (emfq), part, part_id, &p_info, cancellable);
-	em_format_write (EM_FORMAT (emfq), CAMEL_STREAM (mem), &w_info, cancellable);
+	parser = e_mail_parser_new (session);
+	part_list->list = e_mail_parser_parse_part (parser, part, part_id, cancellable);
 	g_string_free (part_id, TRUE);
+	g_object_unref (parser);
+
+	formatter = e_mail_formatter_quote_new (NULL, E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG);
+	e_mail_formatter_set_style (formatter,
+			gtk_widget_get_style (GTK_WIDGET (window)),
+			gtk_widget_get_state (GTK_WIDGET (window)));
 
-	g_object_unref (emfq);
+	e_mail_formatter_format_sync (
+		formatter, part_list, (CamelStream *) mem,
+			0, E_MAIL_FORMATTER_MODE_PRINTING, cancellable);
+	g_object_unref (formatter);
+	g_object_unref (part_list);
 
 	camel_stream_write((CamelStream *) mem, "", 1, cancellable, NULL);
 	g_object_unref (mem);
 
 	text = (gchar *) buf->data;
 	if (len)
-		*len = buf->len-1;
+		*len = buf->len - 1;
 	g_byte_array_free (buf, FALSE);
 
 	return text;
@@ -2711,7 +2716,7 @@ handle_multipart_signed (EMsgComposer *composer,
 		gssize length;
 
 		html = emcu_part_to_html (
-			session, mime_part, &length, NULL, cancellable);
+			session, mime_part, &length, cancellable);
 		e_msg_composer_set_pending_body (composer, html, length);
 	} else {
 		e_msg_composer_attach (composer, mime_part);
@@ -2799,7 +2804,7 @@ handle_multipart_encrypted (EMsgComposer *composer,
 		gssize length;
 
 		html = emcu_part_to_html (
-			session, mime_part, &length, NULL, cancellable);
+			session, mime_part, &length, cancellable);
 		e_msg_composer_set_pending_body (composer, html, length);
 	} else {
 		e_msg_composer_attach (composer, mime_part);
@@ -2880,7 +2885,7 @@ handle_multipart_alternative (EMsgComposer *composer,
 		gssize length;
 
 		html = emcu_part_to_html (
-			session, text_part, &length, NULL, cancellable);
+			session, text_part, &length, cancellable);
 		e_msg_composer_set_pending_body (composer, html, length);
 	}
 }
@@ -2948,7 +2953,7 @@ handle_multipart (EMsgComposer *composer,
 			/* Since the first part is not multipart/alternative,
 			 * this must be the body. */
 			html = emcu_part_to_html (
-				session, mime_part, &length, NULL, cancellable);
+				session, mime_part, &length, cancellable);
 			e_msg_composer_set_pending_body (composer, html, length);
 		} else if (camel_mime_part_get_content_id (mime_part) ||
 			   camel_mime_part_get_content_location (mime_part)) {
@@ -3325,7 +3330,7 @@ e_msg_composer_new_with_message (EShell *shell,
 
 		html = emcu_part_to_html (
 			session, CAMEL_MIME_PART (message),
-			&length, NULL, cancellable);
+			&length, cancellable);
 		e_msg_composer_set_pending_body (composer, html, length);
 	}
 
diff --git a/data/webview.css b/data/webview.css
index 5b0e734..09f9404 100644
--- a/data/webview.css
+++ b/data/webview.css
@@ -58,13 +58,13 @@ img.navigable {
 }
 
 .part-container {
-  width: 100%;
   height: 100%;
   background: #FFF;
   margin-top: 2px;
   margin-bottom: 3px;
   border-width: 1px;
   border-style: solid;
+  right: 0;
 }
 
 .part-container-inner-margin {
diff --git a/em-format/Makefile.am b/em-format/Makefile.am
index 392a195..6b42ec1 100644
--- a/em-format/Makefile.am
+++ b/em-format/Makefile.am
@@ -3,33 +3,118 @@ emformatincludedir = $(privincludedir)/em-format
 privsolib_LTLIBRARIES = libemformat.la
 
 emformatinclude_HEADERS =				\
-	em-format.h					\
-	em-format-quote.h				\
-	em-inline-filter.h				\
-	em-stripsig-filter.h
+	e-mail-extension-registry.h			\
+	e-mail-extension.h				\
+	e-mail-formatter-extension.h			\
+	e-mail-formatter.h				\
+	e-mail-formatter-print.h			\
+	e-mail-formatter-quote.h			\
+	e-mail-formatter-utils.h			\
+	e-mail-inline-filter.h				\
+	e-mail-parser-extension.h			\
+	e-mail-parser.h					\
+	e-mail-part.h					\
+	e-mail-part-attachment.h			\
+	e-mail-part-attachment-bar.h			\
+	e-mail-part-list.h				\
+	e-mail-part-utils.h				\
+	e-mail-stripsig-filter.h
 
 libemformat_la_CPPFLAGS =				\
 	$(AM_CPPFLAGS)					\
 	-I$(top_srcdir)					\
+	-I$(top_srcdir)/em-format			\
+	-I$(top_srcdir)/smime/lib			\
+	-I$(top_srcdir)/smime/gui			\
 	-I$(top_srcdir)/widgets				\
 	$(EVOLUTION_DATA_SERVER_CFLAGS)			\
 	$(GNOME_PLATFORM_CFLAGS)			\
-	$(LIBSOUP_CFLAGS)
+	$(LIBSOUP_CFLAGS)				\
+	-DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\"	\
+	-DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\"
+
+if ENABLE_SMIME
+SMIME_EXTENSIONS = e-mail-parser-application-smime.c
+endif
 
 libemformat_la_SOURCES =				\
 	$(emformatinclude_HEADERS)			\
-	em-format.c					\
-	em-format-quote.c				\
-	em-inline-filter.c				\
-	em-stripsig-filter.c
+	$(emformatextensions_SOURCES)			\
+	e-mail-extension-registry.c			\
+	e-mail-extension.c				\
+	e-mail-inline-filter.c				\
+	e-mail-format-extensions.c			\
+	e-mail-formatter.c				\
+	e-mail-formatter-print.c			\
+	e-mail-formatter-quote.c			\
+	e-mail-formatter-utils.c			\
+	e-mail-formatter-attachment.c			\
+	e-mail-formatter-attachment-bar.c		\
+	e-mail-formatter-error.c			\
+	e-mail-formatter-extension.c			\
+	e-mail-formatter-headers.c			\
+	e-mail-formatter-image.c			\
+	e-mail-formatter-message-rfc822.c		\
+	e-mail-formatter-secure-button.c		\
+	e-mail-formatter-source.c			\
+	e-mail-formatter-text-enriched.c		\
+	e-mail-formatter-text-html.c			\
+	e-mail-formatter-text-plain.c			\
+	e-mail-formatter-print-headers.c		\
+	e-mail-formatter-quote-attachment.c		\
+	e-mail-formatter-quote-headers.c		\
+	e-mail-formatter-quote-message-rfc822.c		\
+	e-mail-formatter-quote-text-enriched.c		\
+	e-mail-formatter-quote-text-html.c		\
+	e-mail-formatter-quote-text-plain.c		\
+	e-mail-parser-extension.c			\
+	e-mail-parser.c					\
+	e-mail-parser-application-mbox.c		\
+	e-mail-parser-attachment-bar.c			\
+	e-mail-parser-headers.c				\
+	e-mail-parser-image.c				\
+	e-mail-parser-inlinepgp-encrypted.c		\
+	e-mail-parser-inlinepgp-signed.c		\
+ 	e-mail-parser-message.c				\
+	e-mail-parser-message-deliverystatus.c		\
+	e-mail-parser-message-external.c		\
+	e-mail-parser-message-rfc822.c			\
+	e-mail-parser-multipart-alternative.c		\
+	e-mail-parser-multipart-appledouble.c		\
+	e-mail-parser-multipart-digest.c		\
+	e-mail-parser-multipart-encrypted.c		\
+	e-mail-parser-multipart-mixed.c			\
+	e-mail-parser-multipart-related.c		\
+	e-mail-parser-multipart-signed.c		\
+	e-mail-parser-secure-button.c			\
+	e-mail-parser-source.c				\
+	e-mail-parser-text-enriched.c			\
+	e-mail-parser-text-html.c			\
+	e-mail-parser-text-plain.c			\
+	e-mail-part.c					\
+	e-mail-part-attachment.c			\
+	e-mail-part-list.c				\
+	e-mail-part-utils.c				\
+	e-mail-stripsig-filter.c			\
+	$(SMIME_EXTENSIONS)
 
 libemformat_la_LDFLAGS = -avoid-version $(NO_UNDEFINED)
 
+
+if ENABLE_SMIME
+SMIME_LIBS =						\
+	$(top_builddir)/smime/lib/libessmime.la		\
+	$(top_builddir)/smime/gui/libevolution-smime.la
+endif
+
 libemformat_la_LIBADD =					\
 	$(top_builddir)/e-util/libeutil.la		\
 	$(top_builddir)/shell/libeshell.la		\
+	$(top_builddir)/libemail-utils/libemail-utils.la	 \
+	$(top_builddir)/libemail-engine/libemail-engine.la	 \
 	$(EVOLUTION_DATA_SERVER_LIBS)			\
 	$(GNOME_PLATFORM_LIBS)				\
-	$(LIBSOUP_LIBS)
+	$(LIBSOUP_LIBS)					\
+	$(SMIME_LIBS)
 
 -include $(top_srcdir)/git.mk
diff --git a/em-format/e-mail-extension-registry.c b/em-format/e-mail-extension-registry.c
new file mode 100644
index 0000000..ef08761
--- /dev/null
+++ b/em-format/e-mail-extension-registry.c
@@ -0,0 +1,294 @@
+/*
+ * e-mail-extension-registry.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <glib-object.h>
+
+#include "e-mail-extension-registry.h"
+#include "e-mail-extension.h"
+#include "e-mail-format-extensions.h"
+#include <libebackend/libebackend.h>
+#include <camel/camel.h>
+
+#include <glib-object.h>
+
+#include <string.h>
+
+#define E_MAIL_EXTENSION_REGISTRY_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_MAIL_EXTENSION_REGISTRY, EMailExtensionRegistryPrivate))
+
+struct _EMailExtensionRegistryPrivate {
+	GHashTable *table;
+};
+
+static gconstpointer parent_class = 0;
+
+G_DEFINE_ABSTRACT_TYPE (
+	EMailExtensionRegistry,
+	e_mail_extension_registry,
+	G_TYPE_OBJECT)
+
+/**
+ * EMailExtensionRegistry:
+ *
+ * The #EMailExtensionRegistry is an abstract class representing a registry
+ * for #EMailExtension<!-//>s.
+ *
+ * #EMailParser and #EMailFormatter both have internally a registry object
+ * based on the #EMailExtensionRegistry.
+ *
+ * One extension can registry itself for more mime-types.
+ */
+
+static void
+mail_extension_registry_finalize (GObject *object)
+{
+	EMailExtensionRegistry *reg = E_MAIL_EXTENSION_REGISTRY (object);
+
+	if (reg->priv->table) {
+		g_hash_table_destroy (reg->priv->table);
+		reg->priv->table = NULL;
+	}
+
+	/* Chain up to parent's finalize() */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+void
+e_mail_extension_registry_class_init (EMailExtensionRegistryClass *klass)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (klass, sizeof (EMailExtensionRegistryPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = mail_extension_registry_finalize;
+}
+
+static void
+destroy_queue (GQueue *queue)
+{
+	g_queue_free_full (queue, g_object_unref);
+}
+
+void
+e_mail_extension_registry_init (EMailExtensionRegistry *reg)
+{
+	reg->priv = E_MAIL_EXTENSION_REGISTRY_GET_PRIVATE (reg);
+
+	reg->priv->table = g_hash_table_new_full (
+		g_str_hash, g_str_equal, NULL, (GDestroyNotify) destroy_queue);
+}
+
+/**
+ * e_mail_extension_registry_add_extension:
+ * @reg: An #EMailExtensionRegistry
+ * @extension: An #EMailExtension
+ *
+ * Registrys the @extension as a handler for all mime-types that it is able
+ * to handle.
+ */
+void
+e_mail_extension_registry_add_extension (EMailExtensionRegistry *reg,
+                                         EMailExtension *extension)
+{
+	gint i;
+	const gchar **types;
+
+	g_return_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg));
+	g_return_if_fail (E_IS_MAIL_EXTENSION (extension));
+
+	/* One reference per extension is enough */
+	g_object_ref (extension);
+
+	types = e_mail_extension_get_mime_types (extension);
+	for (i = 0; types && types[i]; i++) {
+		GQueue *queue;
+
+		queue = g_hash_table_lookup (reg->priv->table, types[i]);
+		if (!queue) {
+			queue = g_queue_new ();
+			g_queue_push_head (queue, extension);
+			g_hash_table_insert (reg->priv->table, (gchar *) types[i], queue);
+		} else {
+			g_queue_push_head (queue, extension);
+		}
+
+		if (camel_debug ("emformat:registry")) {
+			printf("Added extension '%s' for type '%s'\n",
+				 G_OBJECT_TYPE_NAME (extension), types[i]);
+		}
+	}
+}
+
+/**
+ * e_mail_extension_registry_remove_extension:
+ * @reg: An #EMailExtensionRegistry
+ * @extension: An #EMailExtension
+ *
+ * Removes @extension from the registry.
+ */
+void
+e_mail_extension_registry_remove_extension (EMailExtensionRegistry *reg,
+                                            EMailExtension *extension)
+{
+	gint i;
+	const gchar **types;
+
+	g_return_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg));
+	g_return_if_fail (E_IS_MAIL_EXTENSION (extension));
+
+	types = e_mail_extension_get_mime_types (extension);
+	for (i = 0; types && types[i]; i++) {
+		GQueue *queue;
+
+		queue = g_hash_table_lookup (reg->priv->table, types[i]);
+		if (!queue) {
+			i++;
+			continue;
+		}
+
+		g_queue_remove (queue, extension);
+
+		if (camel_debug ("emformat:registry")) {
+			printf("Removed extension '%s' from type '%s'\n",
+				G_OBJECT_TYPE_NAME (extension), types[i]);
+		}
+	}
+
+	g_object_unref (extension);
+}
+
+/**
+ * e_mail_extension_registry_get_for_mime_type:
+ * @reg: An #EMailExtensionRegistry
+ * @mime_type: A string with mime-type to look up
+ *
+ * Tries to lookup list of #EMailExtension<!-//>s that has registryed themselves
+ * as handlers for the @mime_type.
+ *
+ * Return value: Returns #GQueue of #EMailExtension<!-//>s or %NULL when there
+ * are no extension registryed for given @mime_type.
+ */
+GQueue *
+e_mail_extension_registry_get_for_mime_type (EMailExtensionRegistry *reg,
+                                             const gchar *mime_type)
+{
+	g_return_val_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg), NULL);
+	g_return_val_if_fail (mime_type && *mime_type, NULL);
+
+	return g_hash_table_lookup (reg->priv->table, mime_type);
+}
+
+/**
+ * e_mail_extension_registry_get_fallback:
+ * @reg: An #EMailExtensionRegistry
+ * @mime_type: A string with mime-type whose fallback to look up
+ *
+ * Tries to lookup fallback parsers for given mime type. For instance, for
+ * multipart/alternative, it will try to lookup multipart/ * parser.
+ *
+ * Return Value: Returns #QGueue of #EMailExtension<!-//>>s or %NULL when there
+ * are no extensions registryed for the fallback type.
+ */
+GQueue *
+e_mail_extension_registry_get_fallback (EMailExtensionRegistry *reg,
+                                        const gchar *mime_type)
+{
+	gchar *s, *type;
+	gsize len;
+	GQueue *parsers;
+
+	g_return_val_if_fail (E_IS_MAIL_EXTENSION_REGISTRY (reg), NULL);
+	g_return_val_if_fail (mime_type && *mime_type, NULL);
+
+	s = strchr (mime_type, '/');
+	len = s - mime_type;
+
+	s = g_alloca (len);
+	strncpy (s, mime_type, len);
+	type = g_ascii_strdown (s, len);
+	s = g_strdup_printf ("%s/*", type);
+
+	parsers = g_hash_table_lookup (reg->priv->table, s);
+
+	g_free (type);
+	g_free (s);
+
+	return parsers;
+}
+
+/******************************************************************************/
+
+static void e_mail_parser_extension_registry_extensible_interface_init (EExtensibleInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (
+	EMailParserExtensionRegistry,
+	e_mail_parser_extension_registry,
+	E_TYPE_MAIL_EXTENSION_REGISTRY,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_EXTENSIBLE,
+		e_mail_parser_extension_registry_extensible_interface_init));
+
+static void
+e_mail_parser_extension_registry_init (EMailParserExtensionRegistry *parser_ereg)
+{
+
+}
+
+static void
+e_mail_parser_extension_registry_class_init (EMailParserExtensionRegistryClass *klass)
+{
+	e_mail_parser_extension_registry_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_extension_registry_extensible_interface_init (EExtensibleInterface *interface)
+{
+
+}
+
+/******************************************************************************/
+
+static void e_mail_formatter_extension_registry_extensible_interface_init (EExtensibleInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (
+	EMailFormatterExtensionRegistry,
+	e_mail_formatter_extension_registry,
+	E_TYPE_MAIL_EXTENSION_REGISTRY,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_EXTENSIBLE,
+		e_mail_formatter_extension_registry_extensible_interface_init));
+
+static void
+e_mail_formatter_extension_registry_init (EMailFormatterExtensionRegistry *formatter_ereg)
+{
+
+}
+
+static void
+e_mail_formatter_extension_registry_class_init (EMailFormatterExtensionRegistryClass *klass)
+{
+	e_mail_formatter_extension_registry_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_extension_registry_extensible_interface_init (EExtensibleInterface *interface)
+{
+
+}
diff --git a/em-format/e-mail-extension-registry.h b/em-format/e-mail-extension-registry.h
new file mode 100644
index 0000000..a6ddb44
--- /dev/null
+++ b/em-format/e-mail-extension-registry.h
@@ -0,0 +1,156 @@
+/*
+ * e-mail-extension-registry.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_EXTENSION_REGISTRY_H_
+#define E_MAIL_EXTENSION_REGISTRY_H_
+
+#include <em-format/e-mail-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_EXTENSION_REGISTRY \
+	(e_mail_extension_registry_get_type ())
+#define E_MAIL_EXTENSION_REGISTRY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_EXTENSION_REGISTRY, EMailExtensionRegistry))
+#define E_MAIL_EXTENSION_REGISTRY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_EXTENSION_REGISTRY, EMailExtensionRegistryClass))
+#define E_IS_MAIL_EXTENSION_REGISTRY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_EXTENSION_REGISTRY))
+#define E_IS_MAIL_EXTENSION_REGISTRY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_EXTENSION_REGISTRY))
+#define E_MAIL_EXTENSION_REGISTRY_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_EXTENSION_REGISTRY, EMailExtensionRegistryClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailExtensionRegistry EMailExtensionRegistry;
+typedef struct _EMailExtensionRegistryClass EMailExtensionRegistryClass;
+typedef struct _EMailExtensionRegistryPrivate EMailExtensionRegistryPrivate;
+
+struct _EMailExtensionRegistryClass {
+	GObjectClass parent_class;
+};
+
+struct _EMailExtensionRegistry {
+	GObject parent;
+	EMailExtensionRegistryPrivate *priv;
+};
+
+GType		e_mail_extension_registry_get_type	(void);
+
+void		e_mail_extension_registry_add_extension	(EMailExtensionRegistry *reg,
+							 EMailExtension *extension);
+
+void		e_mail_extension_registry_remove_extension
+							(EMailExtensionRegistry *reg,
+							 EMailExtension *extension);
+
+GQueue *	e_mail_extension_registry_get_for_mime_type
+							(EMailExtensionRegistry *reg,
+							 const gchar *mime_type);
+
+GQueue *	e_mail_extension_registry_get_fallback	(EMailExtensionRegistry *reg,
+							 const gchar *mime_type);
+
+G_END_DECLS
+
+/******************************************************************************/
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY \
+	(e_mail_parser_extension_registry_get_type ())
+#define E_MAIL_PARSER_EXTENSION_REGISTRY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, EMailParserExtensionRegistry))
+#define E_MAIL_PARSER_EXTENSION_REGISTRY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, EMailParserExtensionRegistryClass))
+#define E_IS_MAIL_PARSER_EXTENSION_REGISTRY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY))
+#define E_IS_MAIL_PARSER_EXTENSION_REGISTRY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY))
+#define E_MAIL_PARSER_EXTENSION_REGISTRY_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, EMailParserExtensionRegistryClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailParserExtensionRegistry EMailParserExtensionRegistry;
+typedef struct _EMailParserExtensionRegistryClass EMailParserExtensionRegistryClass;
+typedef struct _EMailParserExtensionRegistryPrivate EMailParserExtensionRegistryPrivate;
+
+struct _EMailParserExtensionRegistryClass {
+	EMailExtensionRegistryClass parent_class;
+};
+
+struct _EMailParserExtensionRegistry {
+	EMailExtensionRegistry parent;
+	EMailParserExtensionRegistryPrivate *priv;
+};
+
+GType		e_mail_parser_extension_registry_get_type	(void);
+
+G_END_DECLS
+
+/******************************************************************************/
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY \
+	(e_mail_formatter_extension_registry_get_type ())
+#define E_MAIL_FORMATTER_EXTENSION_REGISTRY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, EMailFormatterExtensionRegistry))
+#define E_MAIL_FORMATTER_EXTENSION_REGISTRY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, EMailFormatterExtensionRegistryClass))
+#define E_IS_MAIL_FORMATTER_EXTENSION_REGISTRY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY))
+#define E_IS_MAIL_FORMATTER_EXTENSION_REGISTRY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY))
+#define E_MAIL_FORMATTER_EXTENSION_REGISTRY_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, EMailFormatterExtensionRegistryClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailFormatterExtensionRegistry EMailFormatterExtensionRegistry;
+typedef struct _EMailFormatterExtensionRegistryClass EMailFormatterExtensionRegistryClass;
+typedef struct _EMailFormatterExtensionRegistryPrivate EMailFormatterExtensionRegistryPrivate;
+
+struct _EMailFormatterExtensionRegistryClass {
+	EMailExtensionRegistryClass parent_class;
+};
+
+struct _EMailFormatterExtensionRegistry {
+	EMailExtensionRegistry parent;
+	EMailFormatterExtensionRegistryPrivate *priv;
+};
+
+GType		e_mail_formatter_extension_registry_get_type	(void);
+
+G_END_DECLS
+
+#endif /* E_MAIL_EXTENSION_REGISTRY_H_ */
diff --git a/em-format/e-mail-extension.c b/em-format/e-mail-extension.c
new file mode 100644
index 0000000..9516974
--- /dev/null
+++ b/em-format/e-mail-extension.c
@@ -0,0 +1,67 @@
+/*
+ * e-mail-extension.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-extension.h"
+
+#include <glib-object.h>
+
+G_DEFINE_INTERFACE (EMailExtension, e_mail_extension, G_TYPE_OBJECT)
+
+static void
+e_mail_extension_default_init (EMailExtensionInterface *iface)
+{
+
+}
+
+/**
+ * EMailExtension:
+ *
+ * The #EMailExtension is an abstract interface for all extensions for
+ * #EMailParser and #EmailFormatter.
+ *
+ * The interface is further extended by #EMailParserExtension and
+ * #EMailFormatterExtension interfaces which define final API for both types
+ * of extensions.
+ */
+
+/**
+ * e_mail_extension_get_mime_types:
+ * @extension: an #EMailExtension
+ *
+ * A virtual function reimplemented in all mail extensions that returns a
+ * @NULL-terminated array of mime types that the particular extension is able
+ * to process.
+ *
+ * The mime-types can be either full (like text/plain), or with common subtype,
+ * e.g. text/ *. User should try to find the best mathing mime-type handler and
+ * use the latter type only as a fallback.
+ *
+ * Return value: a @NULL-terminated array or @NULL
+ */
+const gchar **
+e_mail_extension_get_mime_types (EMailExtension *extension)
+{
+	EMailExtensionInterface *interface;
+
+	g_return_val_if_fail (E_IS_MAIL_EXTENSION (extension), NULL);
+
+	interface = E_MAIL_EXTENSION_GET_INTERFACE (extension);
+	g_return_val_if_fail (interface->mime_types != NULL, NULL);
+
+	return interface->mime_types (extension);
+}
diff --git a/em-format/e-mail-extension.h b/em-format/e-mail-extension.h
new file mode 100644
index 0000000..941638a
--- /dev/null
+++ b/em-format/e-mail-extension.h
@@ -0,0 +1,60 @@
+/*
+ * e-mail-extension.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_EXTENSION_H
+#define E_MAIL_EXTENSION_H
+
+#include <glib-object.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_EXTENSION \
+	(e_mail_extension_get_type ())
+#define E_MAIL_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_EXTENSION, EMailExtension))
+#define E_MAIL_EXTENSION_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_EXTENSION, EMailExtensionInterface))
+#define E_IS_MAIL_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_EXTENSION))
+#define E_IS_MAIL_EXTENSION_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_EXTENSION))
+#define E_MAIL_EXTENSION_GET_INTERFACE(obj) \
+	(G_TYPE_INSTANCE_GET_INTERFACE \
+	((obj), E_TYPE_MAIL_EXTENSION, EMailExtensionInterface))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailExtension EMailExtension;
+typedef struct _EMailExtensionInterface EMailExtensionInterface;
+
+struct _EMailExtensionInterface {
+	GTypeInterface parent_interface;
+
+	const gchar **		(*mime_types)		(EMailExtension *extension);
+};
+
+GType		e_mail_extension_get_type		(void);
+
+const gchar **	e_mail_extension_get_mime_types		(EMailExtension *extension);
+
+G_END_DECLS
+
+#endif /* E_MAIL_EXTENSION_H */
diff --git a/em-format/e-mail-format-extensions.c b/em-format/e-mail-format-extensions.c
new file mode 100644
index 0000000..fa7d5d8
--- /dev/null
+++ b/em-format/e-mail-format-extensions.c
@@ -0,0 +1,124 @@
+/*
+ * e-mail-format-extensions.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-format-extensions.h"
+
+#include "em-format/e-mail-parser-extension.h"
+#include "em-format/e-mail-formatter-extension.h"
+
+typedef GType (*TypeFunc) (void);
+
+TypeFunc parser_funcs[] = {
+	e_mail_parser_application_mbox_get_type,
+	e_mail_parser_attachment_bar_get_type,
+	e_mail_parser_headers_get_type,
+	e_mail_parser_message_get_type,
+	e_mail_parser_secure_button_get_type,
+	e_mail_parser_source_get_type,
+	e_mail_parser_image_get_type,
+	e_mail_parser_inline_pgp_encrypted_get_type,
+	e_mail_parser_inline_pgp_signed_get_type,
+	e_mail_parser_message_delivery_status_get_type,
+	e_mail_parser_message_external_get_type,
+	e_mail_parser_message_rfc822_get_type,
+	e_mail_parser_multipart_alternative_get_type,
+	e_mail_parser_multipart_apple_double_get_type,
+	e_mail_parser_multipart_digest_get_type,
+	e_mail_parser_multipart_encrypted_get_type,
+	e_mail_parser_multipart_mixed_get_type,
+	e_mail_parser_multipart_related_get_type,
+	e_mail_parser_multipart_signed_get_type,
+	e_mail_parser_text_enriched_get_type,
+	e_mail_parser_text_html_get_type,
+	e_mail_parser_text_plain_get_type,
+#ifdef ENABLE_SMIME
+	e_mail_parser_application_smime_get_type,
+#endif
+	NULL
+};
+
+TypeFunc formatter_funcs[] = {
+	e_mail_formatter_attachment_get_type,
+	e_mail_formatter_attachment_bar_get_type,
+	e_mail_formatter_error_get_type,
+	e_mail_formatter_headers_get_type,
+	e_mail_formatter_secure_button_get_type,
+	e_mail_formatter_source_get_type,
+	e_mail_formatter_image_get_type,
+	e_mail_formatter_message_rfc822_get_type,
+	e_mail_formatter_text_enriched_get_type,
+	e_mail_formatter_text_html_get_type,
+	e_mail_formatter_text_plain_get_type,
+	NULL
+};
+
+TypeFunc quote_formatter_funcs[] = {
+	e_mail_formatter_quote_attachment_get_type,
+	e_mail_formatter_quote_headers_get_type,
+	e_mail_formatter_quote_message_rfc822_get_type,
+	e_mail_formatter_quote_text_enriched_get_type,
+	e_mail_formatter_quote_text_html_get_type,
+	e_mail_formatter_quote_text_plain_get_type,
+	NULL
+};
+
+TypeFunc print_formatter_funcs[] = {
+	e_mail_formatter_print_headers_get_type,
+	NULL
+};
+
+static void
+load (EMailExtensionRegistry *ereg,
+      TypeFunc *func_array)
+{
+	gint i = 0;
+
+	for (i = 0; func_array[i] != NULL; i++) {
+		GType type;
+		EMailExtension *extension;
+
+		type = func_array[i]();
+		extension = g_object_new (type, NULL);
+
+		e_mail_extension_registry_add_extension (ereg, extension);
+	}
+}
+
+void
+e_mail_parser_internal_extensions_load (EMailExtensionRegistry *ereg)
+{
+	load (ereg, parser_funcs);
+}
+
+void
+e_mail_formatter_internal_extensions_load (EMailExtensionRegistry *ereg)
+{
+	load (ereg, formatter_funcs);
+}
+
+void
+e_mail_formatter_quote_internal_extensions_load (EMailExtensionRegistry *ereg)
+{
+	load (ereg, quote_formatter_funcs);
+}
+
+void
+e_mail_formatter_print_internal_extensions_load (EMailExtensionRegistry *ereg)
+{
+	load (ereg, print_formatter_funcs);
+}
diff --git a/em-format/e-mail-format-extensions.h b/em-format/e-mail-format-extensions.h
new file mode 100644
index 0000000..74638ef
--- /dev/null
+++ b/em-format/e-mail-format-extensions.h
@@ -0,0 +1,88 @@
+/*
+ * extensions.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef EXTENSIONS_H_
+#define EXTENSIONS_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <em-format/e-mail-extension-registry.h>
+#include <em-format/e-mail-part.h>
+#include <widgets/misc/e-attachment-view.h>
+
+G_BEGIN_DECLS
+
+void	e_mail_formatter_internal_extensions_load	(EMailExtensionRegistry *ereg);
+void	e_mail_parser_internal_extensions_load		(EMailExtensionRegistry *ereg);
+void	e_mail_formatter_quote_internal_extensions_load	(EMailExtensionRegistry *ereg);
+void	e_mail_formatter_print_internal_extensions_load	(EMailExtensionRegistry *ereg);
+
+GType	e_mail_formatter_attachment_get_type		(void);
+GType	e_mail_formatter_attachment_bar_get_type
+							(void);
+GType	e_mail_formatter_error_get_type			(void);
+GType	e_mail_formatter_headers_get_type		(void);
+GType	e_mail_formatter_secure_button_get_type
+							(void);
+GType	e_mail_formatter_source_get_type		(void);
+GType	e_mail_formatter_image_get_type			(void);
+GType	e_mail_formatter_message_rfc822_get_type	(void);
+GType	e_mail_formatter_text_enriched_get_type		(void);
+GType	e_mail_formatter_text_html_get_type		(void);
+GType	e_mail_formatter_text_plain_get_type		(void);
+
+GType	e_mail_parser_application_mbox_get_type		(void);
+GType	e_mail_parser_attachment_bar_get_type		(void);
+GType	e_mail_parser_headers_get_type			(void);
+GType	e_mail_parser_message_get_type			(void);
+GType	e_mail_parser_secure_button_get_type		(void);
+GType	e_mail_parser_source_get_type			(void);
+GType	e_mail_parser_image_get_type			(void);
+GType	e_mail_parser_inline_pgp_encrypted_get_type	(void);
+GType	e_mail_parser_inline_pgp_signed_get_type	(void);
+GType	e_mail_parser_message_delivery_status_get_type	(void);
+GType	e_mail_parser_message_external_get_type		(void);
+GType	e_mail_parser_message_rfc822_get_type		(void);
+GType	e_mail_parser_multipart_alternative_get_type	(void);
+GType	e_mail_parser_multipart_apple_double_get_type	(void);
+GType	e_mail_parser_multipart_digest_get_type		(void);
+GType	e_mail_parser_multipart_encrypted_get_type	(void);
+GType	e_mail_parser_multipart_mixed_get_type		(void);
+GType	e_mail_parser_multipart_related_get_type	(void);
+GType	e_mail_parser_multipart_signed_get_type		(void);
+GType	e_mail_parser_text_enriched_get_type		(void);
+GType	e_mail_parser_text_html_get_type		(void);
+GType	e_mail_parser_text_plain_get_type		(void);
+#ifdef ENABLE_SMIME
+GType	e_mail_parser_application_smime_get_type	(void);
+#endif
+
+GType	e_mail_formatter_quote_attachment_get_type	(void);
+GType	e_mail_formatter_quote_headers_get_type		(void);
+GType	e_mail_formatter_quote_message_rfc822_get_type	(void);
+GType	e_mail_formatter_quote_text_enriched_get_type	(void);
+GType	e_mail_formatter_quote_text_html_get_type	(void);
+GType	e_mail_formatter_quote_text_plain_get_type	(void);
+
+GType	e_mail_formatter_print_headers_get_type		(void);
+
+G_END_DECLS
+
+#endif /* EXTENSIONS_H_ */
diff --git a/em-format/e-mail-formatter-attachment-bar.c b/em-format/e-mail-formatter-attachment-bar.c
new file mode 100644
index 0000000..c1fda16
--- /dev/null
+++ b/em-format/e-mail-formatter-attachment-bar.c
@@ -0,0 +1,154 @@
+/*
+ * e-mail-formatter-attachment-bar.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "e-mail-format-extensions.h"
+#include "e-mail-part-attachment-bar.h"
+#include <misc/e-attachment-bar.h>
+
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+
+typedef struct _EMailFormatterAttachmentBar {
+	GObject parent;
+} EMailFormatterAttachmentBar;
+
+typedef struct _EMailFormatterAttachmentBarClass {
+	GObjectClass parent_class;
+} EMailFormatterAttachmentBarClass;
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterAttachmentBar,
+	e_mail_formatter_attachment_bar,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interface_init));
+
+static const gchar *formatter_mime_types[] = { "application/vnd.evolution.widget.attachment-bar", NULL };
+
+static gboolean
+emfe_attachment_bar_format (EMailFormatterExtension *extension,
+                            EMailFormatter *formatter,
+                            EMailFormatterContext *context,
+                            EMailPart *part,
+                            CamelStream *stream,
+                            GCancellable *cancellable)
+{
+	gchar *str;
+
+	if ((context->mode != E_MAIL_FORMATTER_MODE_NORMAL) &&
+	    (context->mode != E_MAIL_FORMATTER_MODE_RAW))
+		return FALSE;
+
+	str = g_strdup_printf (
+		"<object type=\"application/vnd.evolution.widget.attachment-bar\" "
+		"height=\"0\" width=\"100%%\" data=\"%s\" id=\"%s\"></object>",
+		part->id, part->id);
+
+	camel_stream_write_string (stream, str, cancellable, NULL);
+
+	g_free (str);
+	return TRUE;
+}
+
+static void
+unset_bar_from_store_data (GObject *store,
+                           EAttachmentBar *bar)
+{
+	/*
+	if (E_IS_ATTACHMENT_STORE (store))
+		g_object_set_data (store, "attachment-bar", NULL);
+	*/
+}
+
+static GtkWidget *
+emfe_attachment_bar_get_widget (EMailFormatterExtension *extension,
+                                EMailPartList *context,
+                                EMailPart *part,
+                                GHashTable *params)
+{
+	EMailPartAttachmentBar *empab;
+	GtkWidget *widget;
+
+	g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartAttachmentBar), NULL);
+
+	empab = (EMailPartAttachmentBar *) part;
+	widget = e_attachment_bar_new (empab->store);
+	g_object_set_data (G_OBJECT (empab->store), "attachment-bar", widget);
+	g_object_weak_ref (G_OBJECT (widget),
+			(GWeakNotify) unset_bar_from_store_data, empab->store);
+
+	return widget;
+}
+
+static const gchar *
+emfe_attachment_bar_get_display_name (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar *
+emfe_attachment_bar_get_description (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar **
+emfe_attachment_bar_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_attachment_bar_class_init (EMailFormatterAttachmentBarClass *klass)
+{
+	e_mail_formatter_attachment_bar_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_attachment_bar_format;
+	iface->get_widget = emfe_attachment_bar_get_widget;
+	iface->get_display_name = emfe_attachment_bar_get_display_name;
+	iface->get_description = emfe_attachment_bar_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_attachment_bar_mime_types;
+}
+
+static void
+e_mail_formatter_attachment_bar_init (EMailFormatterAttachmentBar *extension)
+{
+
+}
diff --git a/em-format/e-mail-formatter-attachment.c b/em-format/e-mail-formatter-attachment.c
new file mode 100644
index 0000000..3d63413
--- /dev/null
+++ b/em-format/e-mail-formatter-attachment.c
@@ -0,0 +1,403 @@
+/*
+ * e-mail-formatter-attachment.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+#include "e-mail-part-attachment.h"
+#include "e-mail-part-attachment-bar.h"
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-part-utils.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <e-util/e-util.h>
+
+#include <shell/e-shell.h>
+#include <shell/e-shell-window.h>
+
+#include <widgets/misc/e-attachment-button.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+#define d(x)
+
+typedef struct _EMailFormatterAttachment {
+	GObject parent;
+} EMailFormatterAttachment;
+
+typedef struct _EMailFormatterAttachmentClass {
+	GObjectClass parent_class;
+} EMailFormatterAttachmentClass;
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterAttachment,
+	e_mail_formatter_attachment,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interface_init)
+)
+
+static const gchar *formatter_mime_types[] = { "application/vnd.evolution.attachment",
+					       "application/vnd.evolution.widget.attachment-button",
+					       NULL };
+
+static EAttachmentStore *
+find_attachment_store (GSList *parts,
+                       const gchar *start_id)
+{
+	gchar *tmp, *pos;
+	EMailPart *part;
+	gchar *id;
+
+	id = g_strconcat (start_id, ".attachment-bar", NULL);
+	tmp = g_strdup (id);
+	part = NULL;
+	do {
+		GSList *iter;
+
+		d(printf("Looking up attachment bar as %s\n", id));
+
+		for (iter = parts; iter; iter = iter->next) {
+			EMailPart *p = iter->data;
+
+			if (!p)
+				continue;
+
+			if (g_strcmp0 (p->id, id) == 0) {
+				part = p;
+				break;
+			}
+		}
+
+		pos = g_strrstr (tmp, ".");
+		if (!pos)
+			break;
+
+		g_free (id);
+		g_free (tmp);
+		tmp = g_strndup (start_id, pos - tmp);
+		id = g_strdup_printf ("%s.attachment-bar", tmp);
+
+	} while (pos && !part);
+
+	g_free (id);
+	g_free (tmp);
+
+	if (part) {
+		return ((EMailPartAttachmentBar *) part)->store;
+	}
+
+	return NULL;
+}
+
+static gboolean
+emfe_attachment_format (EMailFormatterExtension *extension,
+                        EMailFormatter *formatter,
+                        EMailFormatterContext *context,
+                        EMailPart *part,
+                        CamelStream *stream,
+                        GCancellable *cancellable)
+{
+	gchar *str, *text, *html;
+	gchar *button_id;
+	EAttachmentStore *store;
+	EMailExtensionRegistry *reg;
+	GQueue *extensions;
+	EMailPartAttachment *empa;
+	gchar *attachment_part_id;
+
+	g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartAttachment), FALSE);
+
+	empa = (EMailPartAttachment *) part;
+
+	if ((context->mode == E_MAIL_FORMATTER_MODE_NORMAL) ||
+	    (context->mode == E_MAIL_FORMATTER_MODE_PRINTING)) {
+		if (part->validity) {
+			e_attachment_set_signed (
+				empa->attachment, part->validity->sign.status);
+			e_attachment_set_encrypted (
+				empa->attachment, part->validity->encrypt.status);
+		}
+
+		store = find_attachment_store (context->parts, part->id);
+		if (store) {
+			GList *attachments = e_attachment_store_get_attachments (store);
+			if (!g_list_find (attachments, empa->attachment)) {
+				e_attachment_store_add_attachment (
+					store, empa->attachment);
+			}
+			g_list_free (attachments);
+		} else {
+			g_warning ("Failed to locate attachment-bar for %s", part->id);
+		}
+	}
+
+        /* If the attachment is requested as RAW, then call the handler directly
+         * and do not append any other code. */
+	if ((context->mode == E_MAIL_FORMATTER_MODE_RAW) ||
+	    (context->mode == E_MAIL_FORMATTER_MODE_PRINTING)) {
+		EMailExtensionRegistry *reg;
+		GQueue *extensions;
+		GList *iter;
+		reg = e_mail_formatter_get_extension_registry (formatter);
+
+		extensions = e_mail_extension_registry_get_for_mime_type (
+					reg, empa->snoop_mime_type);
+		if (!extensions) {
+			extensions = e_mail_extension_registry_get_fallback (
+					reg, empa->snoop_mime_type);
+		}
+
+		if (!extensions)
+			return FALSE;
+
+		if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
+			gchar *name;
+			EAttachment *attachment;
+			GFileInfo *fi;
+			const gchar *description;
+
+			attachment = empa->attachment;
+			fi = e_attachment_get_file_info (attachment);
+
+			description = e_attachment_get_description (attachment);
+			if (description && *description) {
+				name = g_strdup_printf ("<h2>Attachment: %s (%s)</h2>\n",
+					description, g_file_info_get_display_name (fi));
+			} else {
+				name = g_strdup_printf ("<h2>Attachment: %s</h2>\n",
+					g_file_info_get_display_name (fi));
+			}
+
+			camel_stream_write_string (stream, name, cancellable, NULL);
+			g_free (name);
+		}
+
+		for (iter = g_queue_peek_head_link (extensions); iter; iter = iter->next) {
+
+			EMailFormatterExtension *ext;
+			ext = iter->data;
+			if (!ext)
+				continue;
+
+			if (e_mail_formatter_extension_format (ext, formatter,
+				context, part, stream, cancellable)) {
+				return TRUE;
+			}
+		}
+
+		return FALSE;
+	}
+
+	/* E_MAIL_FORMATTER_MODE_NORMAL: */
+
+	reg = e_mail_formatter_get_extension_registry (formatter);
+	extensions = e_mail_extension_registry_get_for_mime_type (
+				reg, empa->snoop_mime_type);
+
+	if (!extensions) {
+		extensions = e_mail_extension_registry_get_fallback (
+				reg, empa->snoop_mime_type);
+	}
+
+	text = e_mail_part_describe (part->part, empa->snoop_mime_type);
+	html = camel_text_to_html (
+		text, e_mail_formatter_get_text_format_flags (formatter) &
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+	g_free (text);
+
+	if (empa->attachment_view_part_id)
+		attachment_part_id = empa->attachment_view_part_id;
+	else
+		attachment_part_id = part->id;
+
+	button_id = g_strconcat (attachment_part_id, ".attachment_button", NULL);
+
+	str = g_strdup_printf (
+		"<div class=\"attachment\">"
+		"<table width=\"100%%\" border=\"0\">"
+		"<tr valign=\"middle\">"
+		"<td align=\"left\" width=\"100\">"
+		"<object type=\"application/vnd.evolution.widget.attachment-button\" "
+		"height=\"20\" width=\"100\" data=\"%s\" id=\"%s\"></object>"
+		"</td>"
+		"<td align=\"left\">%s</td>"
+		"</tr>", part->id, button_id, html);
+
+	camel_stream_write_string (stream, str, cancellable, NULL);
+	g_free (button_id);
+	g_free (str);
+	g_free (html);
+
+	if (extensions) {
+		GList *iter;
+		CamelStream *content_stream;
+		gboolean ok;
+
+		content_stream = camel_stream_mem_new ();
+		ok = FALSE;
+		if (empa->attachment_view_part_id != NULL) {
+
+			GSList *att_parts;
+
+			att_parts = e_mail_part_list_get_iter (
+						context->parts,
+						empa->attachment_view_part_id);
+
+			if (att_parts && att_parts->data) {
+				ok = e_mail_formatter_format_as (
+					formatter, context, att_parts->data,
+					content_stream, NULL, cancellable);
+			}
+
+		} else {
+
+			for (iter = g_queue_peek_head_link (extensions); iter; iter = iter->next) {
+
+				EMailFormatterExtension *ext;
+
+				ext = iter->data;
+				if (!ext)
+					continue;
+
+				if (e_mail_formatter_extension_format (
+						ext, formatter, context,
+						part, content_stream,
+						cancellable)) {
+					ok = TRUE;
+					break;
+				}
+			}
+		}
+
+		if (ok) {
+			str = g_strdup_printf (
+				"<tr><td colspan=\"2\">"
+				"<div class=\"attachment-wrapper\" id=\"%s\">",
+				attachment_part_id);
+
+			camel_stream_write_string (
+				stream, str, cancellable, NULL);
+			g_free (str);
+
+			g_seekable_seek (
+				G_SEEKABLE (content_stream), 0,
+				G_SEEK_SET, cancellable, NULL);
+			camel_stream_write_to_stream (
+					content_stream, stream,
+					cancellable, NULL);
+
+			camel_stream_write_string (
+				stream, "</div></td></tr>", cancellable, NULL);
+		}
+
+		g_object_unref (content_stream);
+	}
+
+	camel_stream_write_string (stream, "</table></div>", cancellable, NULL);
+
+	return TRUE;
+}
+
+static GtkWidget *
+emfe_attachment_get_widget (EMailFormatterExtension *extension,
+                            EMailPartList *context,
+                            EMailPart *part,
+                            GHashTable *params)
+{
+	EMailPartAttachment *empa;
+	EAttachmentStore *store;
+	EAttachmentView *view;
+	GtkWidget *widget;
+
+	g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartAttachment), NULL);
+	empa = (EMailPartAttachment *) part;
+
+	store = find_attachment_store (context->list, part->id);
+	widget = e_attachment_button_new ();
+	g_object_set_data (G_OBJECT (widget), "uri", part->id);
+	e_attachment_button_set_attachment (
+		E_ATTACHMENT_BUTTON (widget), empa->attachment);
+	view = g_object_get_data (G_OBJECT (store), "attachment-bar");
+	if (view) {
+		e_attachment_button_set_view (
+			E_ATTACHMENT_BUTTON (widget), view);
+	}
+
+	gtk_widget_set_can_focus (widget, TRUE);
+	gtk_widget_show (widget);
+
+	return widget;
+}
+
+static const gchar *
+emfe_attachment_get_display_name (EMailFormatterExtension *extension)
+{
+	return _("Attachment");
+}
+
+static const gchar *
+emfe_attachment_get_description (EMailFormatterExtension *extension)
+{
+	return _("Display as attachment");
+}
+
+static const gchar **
+emfe_attachment_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_attachment_class_init (EMailFormatterAttachmentClass *klass)
+{
+	e_mail_formatter_attachment_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_attachment_format;
+	iface->get_widget = emfe_attachment_get_widget;
+	iface->get_display_name = emfe_attachment_get_display_name;
+	iface->get_description = emfe_attachment_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_attachment_mime_types;
+}
+
+static void
+e_mail_formatter_attachment_init (EMailFormatterAttachment *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-error.c b/em-format/e-mail-formatter-error.c
new file mode 100644
index 0000000..95f2011
--- /dev/null
+++ b/em-format/e-mail-formatter-error.c
@@ -0,0 +1,160 @@
+/*
+ * e-mail-formatter-error.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+typedef struct _EMailFormatterError {
+	GObject parent;
+} EMailFormatterError;
+
+typedef struct _EMailFormatterErrorClass {
+	GObjectClass parent_class;
+} EMailFormatterErrorClass;
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterError,
+	e_mail_formatter_error,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interface_init));
+
+static const gchar *formatter_mime_types[] = { "application/vnd.evolution.error", NULL };
+
+static gboolean
+emfe_error_format (EMailFormatterExtension *extension,
+                   EMailFormatter *formatter,
+                   EMailFormatterContext *context,
+                   EMailPart *part,
+                   CamelStream *stream,
+                   GCancellable *cancellable)
+{
+	CamelStream *filtered_stream;
+	CamelMimeFilter *filter;
+	CamelDataWrapper *dw;
+	gchar *html;
+
+	dw = camel_medium_get_content ((CamelMedium *) part->part);
+
+	html = g_strdup_printf (
+		"<div class=\"part-container\" style=\""
+		"border-color: #%06x;"
+		"background-color: #%06x; color: #%06x;\">"
+		"<div class=\"part-container-inner-margin pre\">\n"
+		"<table border=\"0\" cellspacing=\"10\" "
+		"cellpadding=\"0\" width=\"100%%\">\n"
+		"<tr valign=\"top\"><td width=50>"
+		"<img src=\"gtk-stock://%s/?size=%d\" /></td>\n"
+		"<td style=\"color: red;\">",
+		e_color_to_value ((GdkColor *)
+			e_mail_formatter_get_color (
+				formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+		e_color_to_value ((GdkColor *)
+			e_mail_formatter_get_color (
+				formatter, E_MAIL_FORMATTER_COLOR_BODY)),
+		e_color_to_value ((GdkColor *)
+			e_mail_formatter_get_color (
+				formatter, E_MAIL_FORMATTER_COLOR_TEXT)),
+		GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_DIALOG);
+
+	camel_stream_write_string (stream, html, cancellable, NULL);
+	g_free (html);
+
+	filtered_stream = camel_stream_filter_new (stream);
+	filter = camel_mime_filter_tohtml_new (
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+	camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered_stream), filter);
+	g_object_unref (filter);
+
+	camel_data_wrapper_decode_to_stream_sync (dw, filtered_stream, cancellable, NULL);
+	camel_stream_flush (filtered_stream, cancellable, NULL);
+	g_object_unref (filtered_stream);
+
+	camel_stream_write_string (stream,
+		"</td>\n"
+		"</tr>\n"
+		"</table>\n"
+		"</div>\n"
+		"</div>",
+		cancellable, NULL);
+
+	return TRUE;
+}
+
+static const gchar *
+emfe_error_get_display_name (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar *
+emfe_error_get_description (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar **
+emfe_error_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_error_class_init (EMailFormatterErrorClass *klass)
+{
+	e_mail_formatter_error_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_error_format;
+	iface->get_display_name = emfe_error_get_display_name;
+	iface->get_description = emfe_error_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_error_mime_types;
+}
+
+static void
+e_mail_formatter_error_init (EMailFormatterError *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-extension.c b/em-format/e-mail-formatter-extension.c
new file mode 100644
index 0000000..381855b
--- /dev/null
+++ b/em-format/e-mail-formatter-extension.c
@@ -0,0 +1,189 @@
+/*
+ * e-mail-formatter-extension.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-formatter-extension.h"
+
+G_DEFINE_INTERFACE (
+	EMailFormatterExtension,
+	e_mail_formatter_extension,
+	E_TYPE_MAIL_EXTENSION)
+
+/**
+ * EMailFormatterExtension:
+ *
+ * The #EMailFormatterExtension is an abstract interface for all extensions for
+ * #EmailFormatter.
+ */
+
+static void
+e_mail_formatter_extension_default_init (EMailFormatterExtensionInterface *iface)
+{
+
+}
+
+/**
+ * e_mail_formatter_extension_format
+ * @extension: an #EMailFormatterExtension
+ * @formatter: an #EMailFormatter
+ * @context: an #EMailFormatterContext
+ * @part: a #EMailPart to be formatter
+ * @stream: a #CamelStream to which the output should be written
+ * @cancellable: (allow-none) a #GCancellable
+ *
+ * A virtual function reimplemented in all mail formatter extensions. The function
+ * formats @part, generated HTML (or other format that can be displayed to user)
+ * and writes it to the @stream.
+ *
+ * When the function is unable to format the @part (either because it's broken
+ * or because it is a different mimetype then the extension is specialized for), the
+ * function will return @FALSE indicating the #EMailFormatter, that it should pick
+ * another extension.
+ *
+ * Implementation of this function must be thread-safe.
+ *
+ * Return value: Returns @TRUE when the @part was successfully formatted and
+ * data were written to the @stream, @FALSE otherwise.
+ */
+gboolean
+e_mail_formatter_extension_format (EMailFormatterExtension *extension,
+                                   EMailFormatter *formatter,
+                                   EMailFormatterContext *context,
+                                   EMailPart *part,
+                                   CamelStream *stream,
+                                   GCancellable *cancellable)
+{
+	EMailFormatterExtensionInterface *interface;
+
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), FALSE);
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+	g_return_val_if_fail (context != NULL, FALSE);
+	g_return_val_if_fail (part != NULL, FALSE);
+	g_return_val_if_fail (CAMEL_IS_STREAM (stream), FALSE);
+
+	interface = E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE (extension);
+	g_return_val_if_fail (interface->format != NULL, FALSE);
+
+	return interface->format (extension, formatter, context, part, stream, cancellable);
+}
+
+/**
+ * e_mail_formatter_extension_has_widget:
+ * @extension: an #EMailFormatterExtension
+ *
+ * Returns whether the extension can provide a GtkWidget.
+ *
+ * Return value: Returns %TRUE when @extension reimplements get_widget(), %FALSE
+ * otherwise.
+ */
+gboolean
+e_mail_formatter_extension_has_widget (EMailFormatterExtension *extension)
+{
+	EMailFormatterExtensionInterface *interface;
+
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), FALSE);
+
+	interface = E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE (extension);
+
+	return (interface->get_widget != NULL);
+}
+
+/**
+ * e_mail_formatter_extension_get_widget:
+ * @extension: an #EMailFormatterExtension
+ * @part: an #EMailPart
+ * @params: a #GHashTable
+ *
+ * A virtual function reimplemented in some mail formatter extensions. The function
+ * should construct a #GtkWidget for given @part. The @params hash table can contain
+ * additional parameters listed in the &lt;object&gt; HTML element that has requested
+ * the widget.
+ *
+ * When @bind_dom_func is not %NULL, the callee will set a callback function
+ * which should be called when the webpage is completely rendered to setup
+ * bindings between DOM events and the widget.
+ *
+ * Return value: Returns a #GtkWidget or %NULL, when error occurs or given @extension
+ * does not reimplement this method.
+ */
+GtkWidget *
+e_mail_formatter_extension_get_widget (EMailFormatterExtension *extension,
+                                       EMailPartList *context,
+                                       EMailPart *part,
+                                       GHashTable *params)
+{
+	EMailFormatterExtensionInterface *interface;
+	GtkWidget *widget;
+
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), NULL);
+	g_return_val_if_fail (part != NULL, NULL);
+	g_return_val_if_fail (params != NULL, NULL);
+
+	interface = E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE (extension);
+
+	widget = NULL;
+	if (interface->get_widget) {
+		widget = interface->get_widget (
+				extension, context, part, params);
+	}
+
+	return widget;
+}
+
+/**
+ * e_mail_formatter_extension_get_display_name:
+ * @extension: an #EMailFormatterExtension
+ *
+ * A virtual function reimplemented in all formatter extensions. It returns a
+ * short name of the extension that can be displayed in user interface.
+ *
+ * Return value: A (localized) string with name of the extension
+ */
+const gchar *
+e_mail_formatter_extension_get_display_name (EMailFormatterExtension *extension)
+{
+	EMailFormatterExtensionInterface *interface;
+
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), NULL);
+
+	interface = E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE (extension);
+	g_return_val_if_fail (interface->get_display_name != NULL, NULL);
+
+	return interface->get_display_name (extension);
+}
+
+/**
+ * e_mail_formatter_extension_get_description:
+ * @extension: an #EMailFormatterExtension
+ *
+ * A virtual function reimplemented in all formatter extensions. It returns a
+ * longer description of capabilities of the extension.
+ *
+ * Return value: A (localized) string with description of the extension.
+ */
+const gchar *
+e_mail_formatter_extension_get_description (EMailFormatterExtension *extension)
+{
+	EMailFormatterExtensionInterface *interface;
+
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), NULL);
+
+	interface = E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE (extension);
+	g_return_val_if_fail (interface->get_description != NULL, NULL);
+
+	return interface->get_description (extension);
+}
diff --git a/em-format/e-mail-formatter-extension.h b/em-format/e-mail-formatter-extension.h
new file mode 100644
index 0000000..e2c4ee6
--- /dev/null
+++ b/em-format/e-mail-formatter-extension.h
@@ -0,0 +1,106 @@
+/*
+ * e-mail-formatter-extension.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_EXTENSION_H
+#define E_MAIL_FORMATTER_EXTENSION_H
+
+#include <em-format/e-mail-extension.h>
+#include <em-format/e-mail-part.h>
+#include <em-format/e-mail-formatter.h>
+#include <camel/camel.h>
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_FORMATTER_EXTENSION \
+	(e_mail_formatter_extension_get_type ())
+#define E_MAIL_FORMATTER_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_FORMATTER_EXTENSION, EMailFormatterExtension))
+#define E_MAIL_FORMATTER_EXTENSION_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_FORMATTER_EXTENSION, EMailFormatterExtensionInterface))
+#define E_IS_MAIL_FORMATTER_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_FORMATTER_EXTENSION))
+#define E_IS_MAIL_FORMATTER_EXTENSION_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_FORMATTER_EXTENSION))
+#define E_MAIL_FORMATTER_EXTENSION_GET_INTERFACE(obj) \
+	(G_TYPE_INSTANCE_GET_INTERFACE \
+	((obj), E_TYPE_MAIL_FORMATTER_EXTENSION, EMailFormatterExtensionInterface))
+
+#define EMF_EXTENSION_GET_FORMATTER(e) \
+	E_MAIL_FORMATTER (e_extension_get_extensible (E_EXTENSION (e)))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailFormatterExtension EMailFormatterExtension;
+typedef struct _EMailFormatterExtensionInterface EMailFormatterExtensionInterface;
+
+struct _EMailFormatterExtensionInterface {
+	EMailExtensionInterface	parent_interface;
+
+	gboolean	(*format)	(EMailFormatterExtension *extension,
+					 EMailFormatter *formatter,
+					 EMailFormatterContext *context,
+					 EMailPart *part,
+					 CamelStream *stream,
+					 GCancellable *cancellable);
+
+	GtkWidget *	(*get_widget)	(EMailFormatterExtension *extension,
+					 EMailPartList *context,
+					 EMailPart *part,
+					 GHashTable *params);
+
+	const gchar *	(*get_display_name)
+					(EMailFormatterExtension *extension);
+
+	const gchar *	(*get_description)
+					(EMailFormatterExtension *extension);
+
+};
+
+GType		e_mail_formatter_extension_get_type
+						(void);
+
+gboolean	e_mail_formatter_extension_format
+						(EMailFormatterExtension *extension,
+						 EMailFormatter *formatter,
+						 EMailFormatterContext *context,
+						 EMailPart *part,
+						 CamelStream *stream,
+						 GCancellable *cancellable);
+
+gboolean	e_mail_formatter_extension_has_widget
+						(EMailFormatterExtension *extension);
+
+GtkWidget *	e_mail_formatter_extension_get_widget
+						(EMailFormatterExtension *extension,
+						 EMailPartList *context,
+						 EMailPart *part,
+						 GHashTable *params);
+
+const gchar *	e_mail_formatter_extension_get_display_name
+						(EMailFormatterExtension *extension);
+
+const gchar *	e_mail_formatter_extension_get_description
+						(EMailFormatterExtension *extension);
+
+G_END_DECLS
+
+#endif /* E_MAIL_FORMATTER_EXTENSION_H */
diff --git a/em-format/e-mail-formatter-headers.c b/em-format/e-mail-formatter-headers.c
new file mode 100644
index 0000000..24d2713
--- /dev/null
+++ b/em-format/e-mail-formatter-headers.c
@@ -0,0 +1,615 @@
+/*
+ * e-mail-formatter-headers.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-formatter-utils.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <libemail-engine/e-mail-utils.h>
+#include <libedataserver/libedataserver.h>
+#include <e-util/e-util.h>
+#include <shell/e-shell.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailFormatterHeaders {
+	GObject parent;
+} EMailFormatterHeaders;
+
+typedef struct _EMailFormatterHeadersClass {
+	GObjectClass parent_class;
+} EMailFormatterHeadersClass;
+
+static const gchar *formatter_mime_types[] = { "application/vnd.evolution.headers", NULL };
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterHeaders,
+	e_mail_formatter_headers,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interface_init))
+
+static void
+format_short_headers (EMailFormatter *formatter,
+                      GString *buffer,
+                      CamelMedium *part,
+                      guint32 flags,
+                      GCancellable *cancellable)
+{
+	const gchar *charset;
+	CamelContentType *ct;
+	const gchar *hdr_charset;
+	gchar *evolution_imagesdir;
+	gchar *subject = NULL;
+	struct _camel_header_address *addrs = NULL;
+	struct _camel_header_raw *header;
+	GString *from;
+	gboolean is_rtl;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	ct = camel_mime_part_get_content_type ((CamelMimePart *) part);
+	charset = camel_content_type_param (ct, "charset");
+	charset = camel_iconv_charset_name (charset);
+	hdr_charset = e_mail_formatter_get_charset (formatter) ?
+			e_mail_formatter_get_charset (formatter) :
+			e_mail_formatter_get_default_charset (formatter);
+
+	evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
+	from = g_string_new ("");
+
+	g_string_append_printf (buffer,
+		"<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" "
+		       "id=\"__evo-short-headers\" style=\"display: %s\">",
+		flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED ? "block" : "none");
+
+	header = ((CamelMimePart *) part)->headers;
+	while (header) {
+		if (!g_ascii_strcasecmp (header->name, "From")) {
+			GString *tmp;
+			if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) {
+				header = header->next;
+				continue;
+			}
+			tmp = g_string_new ("");
+			e_mail_formatter_format_address (
+				formatter, tmp, addrs, header->name, FALSE,
+				!(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE));
+
+			if (tmp->len)
+				g_string_printf (from, _("From: %s"), tmp->str);
+			g_string_free (tmp, TRUE);
+
+		} else if (!g_ascii_strcasecmp (header->name, "Subject")) {
+			gchar *buf = NULL;
+			subject = camel_header_unfold (header->value);
+			buf = camel_header_decode_string (subject, hdr_charset);
+			g_free (subject);
+			subject = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0);
+			g_free (buf);
+		}
+		header = header->next;
+	}
+
+	is_rtl = gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL;
+	if (is_rtl) {
+		g_string_append_printf (
+			buffer,
+			"<tr><td width=\"100%%\" align=\"right\">%s%s%s <strong>%s</strong></td></tr>",
+			from->len ? "(" : "", from->str, from->len ? ")" : "",
+			subject ? subject : _("(no subject)"));
+	} else {
+		g_string_append_printf (
+			buffer,
+			"<tr><td><strong>%s</strong> %s%s%s</td></tr>",
+			subject ? subject : _("(no subject)"),
+			from->len ? "(" : "", from->str, from->len ? ")" : "");
+	}
+
+	g_string_append (buffer, "</table>");
+
+	g_free (subject);
+	if (addrs)
+		camel_header_address_list_clear (&addrs);
+
+	g_string_free (from, TRUE);
+	g_free (evolution_imagesdir);
+}
+
+static void
+write_contact_picture (CamelMimePart *part,
+                       gint size,
+                       GString *buffer)
+{
+	gchar *b64, *content_type;
+	CamelDataWrapper *dw;
+	CamelContentType *ct;
+	GByteArray *ba;
+
+	ba = NULL;
+	dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+	if (dw) {
+		ba = camel_data_wrapper_get_byte_array (dw);
+	}
+
+	if (!ba || ba->len == 0) {
+
+		if (camel_mime_part_get_filename (part)) {
+
+			if (size >= 0) {
+				g_string_append_printf (
+					buffer,
+			    		"<img width=\"%d\" src=\"evo-file://%s\" />",
+					size, camel_mime_part_get_filename (part));
+			} else {
+				g_string_append_printf (
+					buffer,
+			    		"<img src=\"evo-file://%s\" />",
+					camel_mime_part_get_filename (part));
+			}
+		}
+
+		return;
+	}
+
+	b64 = g_base64_encode (ba->data, ba->len);
+	ct = camel_mime_part_get_content_type (part);
+	content_type = camel_content_type_simple (ct);
+
+	if (size >= 0) {
+		g_string_append_printf (
+			buffer,
+			"<img width=\"%d\" src=\"data:%s;base64,%s\">",
+			size, content_type, b64);
+	} else {
+		g_string_append_printf (
+			buffer,
+			"<img src=\"data:%s;base64,%s\">",
+			content_type, b64);
+	}
+
+	g_free (b64);
+	g_free (content_type);
+}
+
+static CamelMimePart *
+load_picture_from_file (const gchar *mime_type,
+                         const gchar *filename,
+                         GCancellable *cancellable)
+{
+	CamelMimePart *part;
+	CamelStream *stream;
+	CamelDataWrapper *dw;
+	gchar *basename;
+
+	stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL);
+	if (stream == NULL)
+		return NULL;
+
+	dw = camel_data_wrapper_new ();
+	camel_data_wrapper_construct_from_stream_sync (
+		dw, stream, cancellable, NULL);
+	g_object_unref (stream);
+	if (mime_type)
+		camel_data_wrapper_set_mime_type (dw, mime_type);
+	part = camel_mime_part_new ();
+	camel_medium_set_content ((CamelMedium *) part, dw);
+	g_object_unref (dw);
+	basename = g_path_get_basename (filename);
+	camel_mime_part_set_filename (part, basename);
+	g_free (basename);
+
+	return part;
+}
+
+static void
+format_full_headers (EMailFormatter *formatter,
+                     GString *buffer,
+                     CamelMedium *part,
+                     guint32 flags,
+                     GCancellable *cancellable)
+{
+	const gchar *charset;
+	CamelContentType *ct;
+	struct _camel_header_raw *header;
+	gboolean have_icon = FALSE;
+	const gchar *photo_name = NULL;
+	CamelInternetAddress *cia = NULL;
+	EShell *shell;
+	ESourceRegistry *registry;
+	gboolean face_decoded  = FALSE, contact_has_photo = FALSE;
+	guchar *face_header_value = NULL;
+	gsize face_header_len = 0;
+	gchar *header_sender = NULL, *header_from = NULL, *name;
+	gboolean mail_from_delegate = FALSE;
+	const gchar *hdr_charset;
+	gchar *evolution_imagesdir;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	shell = e_shell_get_default ();
+	registry = e_shell_get_registry (shell);
+
+	ct = camel_mime_part_get_content_type ((CamelMimePart *) part);
+	charset = camel_content_type_param (ct, "charset");
+	charset = camel_iconv_charset_name (charset);
+	hdr_charset = e_mail_formatter_get_charset (formatter) ?
+			e_mail_formatter_get_charset (formatter) :
+			e_mail_formatter_get_default_charset (formatter);
+
+	evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
+
+	g_string_append_printf (buffer,
+		"<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" "
+		       "id=\"__evo-full-headers\" style=\"display: %s\" width=\"100%%\">",
+		flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED ? "none" : "block");
+
+	header = ((CamelMimePart *) part)->headers;
+	while (header) {
+		if (!g_ascii_strcasecmp (header->name, "Sender")) {
+			struct _camel_header_address *addrs;
+			GString *html;
+
+			if (!(addrs = camel_header_address_decode (header->value, hdr_charset)))
+				break;
+
+			html = g_string_new("");
+			name = e_mail_formatter_format_address (
+					formatter, html, addrs, header->name, FALSE,
+					~(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE));
+
+			header_sender = html->str;
+			camel_header_address_list_clear (&addrs);
+
+			g_string_free (html, FALSE);
+			g_free (name);
+		} else if (!g_ascii_strcasecmp (header->name, "From")) {
+			struct _camel_header_address *addrs;
+			GString *html;
+
+			if (!(addrs = camel_header_address_decode (header->value, hdr_charset)))
+				break;
+
+			html = g_string_new("");
+			name = e_mail_formatter_format_address (
+					formatter, html, addrs, header->name, FALSE,
+					!(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE));
+
+			header_from = html->str;
+			camel_header_address_list_clear (&addrs);
+
+			g_string_free (html, FALSE);
+			g_free (name);
+		} else if (!g_ascii_strcasecmp (header->name, "X-Evolution-Mail-From-Delegate")) {
+			mail_from_delegate = TRUE;
+		}
+
+		header = header->next;
+	}
+
+	if (header_sender && header_from && mail_from_delegate) {
+		gchar *bold_sender, *bold_from;
+
+		g_string_append (
+			buffer,
+			"<tr><td><table border=1 width=\"100%%\" "
+			"cellspacing=2 cellpadding=2><tr>");
+		if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
+			g_string_append (
+				buffer, "<td align=\"right\" width=\"100%%\">");
+		else
+			g_string_append (
+				buffer, "<td align=\"left\" width=\"100%%\">");
+		bold_sender = g_strconcat ("<b>", header_sender, "</b>", NULL);
+		bold_from = g_strconcat ("<b>", header_from, "</b>", NULL);
+		/* Translators: This message suggests to the receipients
+		 * that the sender of the mail is different from the one
+		 * listed in From field. */
+		g_string_append_printf (
+			buffer,
+			_("This message was sent by %s on behalf of %s"),
+			bold_sender, bold_from);
+		g_string_append (buffer, "</td></tr></table></td></tr>");
+		g_free (bold_sender);
+		g_free (bold_from);
+	}
+
+	g_free (header_sender);
+	g_free (header_from);
+
+	g_string_append (buffer, "<tr><td width=\"100%%\"><table border=0 cellpadding=\"0\">\n");
+
+	g_free (evolution_imagesdir);
+
+	/* dump selected headers */
+	if (flags & E_MAIL_FORMATTER_MODE_ALL_HEADERS) {
+		header = ((CamelMimePart *) part)->headers;
+		while (header) {
+			e_mail_formatter_format_header (
+				formatter, buffer, part, header,
+				E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS, charset);
+			header = header->next;
+		}
+	} else {
+		GList *link;
+		gint mailer_shown = FALSE;
+
+		link = g_queue_peek_head_link (
+				(GQueue *) e_mail_formatter_get_headers (formatter));
+
+		while (link != NULL) {
+			EMailFormatterHeader *h = link->data;
+			gint mailer, face;
+
+			header = ((CamelMimePart *) part)->headers;
+			mailer = !g_ascii_strcasecmp (h->name, "X-Evolution-Mailer");
+			face = !g_ascii_strcasecmp (h->name, "Face");
+
+			while (header) {
+				if (e_mail_formatter_get_show_sender_photo (formatter) &&
+					!photo_name && !g_ascii_strcasecmp (header->name, "From"))
+					photo_name = header->value;
+
+				if (!mailer_shown && mailer && (
+				    !g_ascii_strcasecmp (header->name, "X-Mailer") ||
+				    !g_ascii_strcasecmp (header->name, "User-Agent") ||
+				    !g_ascii_strcasecmp (header->name, "X-Newsreader") ||
+				    !g_ascii_strcasecmp (header->name, "X-MimeOLE"))) {
+					struct _camel_header_raw xmailer, *use_header = NULL;
+
+					if (!g_ascii_strcasecmp (header->name, "X-MimeOLE")) {
+						for (use_header = header->next; use_header; use_header = use_header->next) {
+							if (!g_ascii_strcasecmp (use_header->name, "X-Mailer") ||
+							    !g_ascii_strcasecmp (use_header->name, "User-Agent") ||
+							    !g_ascii_strcasecmp (use_header->name, "X-Newsreader")) {
+								/* even we have X-MimeOLE, then use rather the standard one, when available */
+								break;
+							}
+						}
+					}
+
+					if (!use_header)
+						use_header = header;
+
+					xmailer.name = (gchar *) "X-Evolution-Mailer";
+					xmailer.value = use_header->value;
+					mailer_shown = TRUE;
+
+					e_mail_formatter_format_header (
+						formatter, buffer, part,
+						&xmailer, h->flags, charset);
+					if (strstr(use_header->value, "Evolution"))
+						have_icon = TRUE;
+				} else if (!face_decoded && face && !g_ascii_strcasecmp (header->name, "Face")) {
+					gchar *cp = header->value;
+
+					/* Skip over spaces */
+					while (*cp == ' ')
+						cp++;
+
+					face_header_value = g_base64_decode (
+						cp, &face_header_len);
+					face_header_value = g_realloc (
+						face_header_value,
+						face_header_len + 1);
+					face_header_value[face_header_len] = 0;
+					face_decoded = TRUE;
+				/* Showing an encoded "Face" header makes little sense */
+				} else if (!g_ascii_strcasecmp (header->name, h->name) && !face) {
+					e_mail_formatter_format_header (
+						formatter, buffer, part,
+						header, h->flags, charset);
+				}
+
+				header = header->next;
+			}
+
+			link = g_list_next (link);
+		}
+	}
+
+	g_string_append (buffer, "</table></td>");
+
+	if (photo_name) {
+		CamelMimePart *photopart;
+		gboolean only_local_photo;
+
+		cia = camel_internet_address_new ();
+		camel_address_decode ((CamelAddress *) cia, (const gchar *) photo_name);
+		only_local_photo = e_mail_formatter_get_only_local_photos (formatter);
+		photopart = em_utils_contact_photo (
+			registry, cia, only_local_photo);
+
+		if (photopart) {
+			g_string_append (buffer, "<td align=\"right\" valign=\"top\">");
+			write_contact_picture (photopart, -1, buffer);
+			g_string_append (buffer, "</td>");
+			g_object_unref (photopart);
+		}
+		g_object_unref (cia);
+	}
+
+	if (!contact_has_photo && face_decoded) {
+		CamelMimePart *part;
+
+		part = camel_mime_part_new ();
+		camel_mime_part_set_content (
+			(CamelMimePart *) part,
+			(const gchar *) face_header_value,
+			face_header_len, "image/png");
+
+		g_string_append (buffer, "<td align=\"right\" valign=\"top\">");
+		write_contact_picture (part, 48, buffer);
+		g_string_append (buffer, "</td>");
+
+		g_object_unref (part);
+		g_free (face_header_value);
+	}
+
+	if (have_icon) {
+		GtkIconInfo *icon_info;
+		CamelMimePart *iconpart = NULL;
+
+		icon_info = gtk_icon_theme_lookup_icon (
+				gtk_icon_theme_get_default (),
+				"evolution", 16, GTK_ICON_LOOKUP_NO_SVG);
+		if (icon_info != NULL) {
+			iconpart = load_picture_from_file (
+				"image/png", gtk_icon_info_get_filename (icon_info),
+				cancellable);
+			gtk_icon_info_free (icon_info);
+		}
+		if (iconpart) {
+			g_string_append (buffer, "<td align=\"right\" valign=\"top\">");
+			write_contact_picture (iconpart, 16, buffer);
+			g_string_append (buffer, "</td>");
+
+			g_object_unref (iconpart);
+		}
+	}
+
+	g_string_append (buffer, "</tr></table>");
+}
+
+static gboolean
+emfe_headers_format (EMailFormatterExtension *extension,
+                     EMailFormatter *formatter,
+                     EMailFormatterContext *context,
+                     EMailPart *part,
+                     CamelStream *stream,
+                     GCancellable *cancellable)
+{
+	GString *buffer;
+	gint bg_color;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return FALSE;
+
+	if (!part->part)
+		return FALSE;
+
+	buffer = g_string_new ("");
+
+	if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
+		GdkColor white = { 0, G_MAXUINT16, G_MAXUINT16, G_MAXUINT16 };
+		bg_color = e_color_to_value (&white);
+	} else {
+		bg_color = e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_BODY));
+	}
+
+	g_string_append_printf (
+		buffer,
+		"<div class=\"headers\" style=\"background: #%06x;\">"
+		"<table border=\"0\" width=\"100%%\" style=\"color: #%06x;\">\n"
+		"<tr><td valign=\"top\" width=\"16\">\n",
+		bg_color,
+		e_color_to_value ((GdkColor *)
+			e_mail_formatter_get_color (
+				formatter,
+				E_MAIL_FORMATTER_COLOR_HEADER)));
+
+	if (context->flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE) {
+		g_string_append_printf (buffer,
+			"<img src=\"evo-file://%s/%s\" class=\"navigable\" "
+			     "id=\"__evo-collapse-headers-img\" />"
+			"</td><td>",
+			EVOLUTION_IMAGESDIR,
+			(context->flags & E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED) ?
+				"plus.png" : "minus.png");
+
+		format_short_headers (formatter, buffer,
+			(CamelMedium *) part->part, context->flags, cancellable);
+	}
+
+	format_full_headers (formatter, buffer,
+		(CamelMedium *) part->part, context->flags, cancellable);
+
+	g_string_append (buffer, "</td></tr></table></div>");
+
+	camel_stream_write_string (stream, buffer->str, cancellable, NULL);
+
+	g_string_free (buffer, TRUE);
+
+	return TRUE;
+}
+
+static const gchar *
+emfe_headers_get_display_name (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar *
+emfe_headers_get_description (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar **
+emfe_headers_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_headers_class_init (EMailFormatterHeadersClass *klass)
+{
+	e_mail_formatter_headers_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_headers_format;
+	iface->get_display_name = emfe_headers_get_display_name;
+	iface->get_description = emfe_headers_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_headers_mime_types;
+}
+
+static void
+e_mail_formatter_headers_init (EMailFormatterHeaders *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-image.c b/em-format/e-mail-formatter-image.c
new file mode 100644
index 0000000..890e9f3
--- /dev/null
+++ b/em-format/e-mail-formatter-image.c
@@ -0,0 +1,191 @@
+/*
+ * image-any.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-part-utils.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+static const gchar *formatter_mime_types[] = { "image/gif", "image/jpeg",
+					       "image/png", "image/x-png",
+					       "image/x-bmp", "image/bmp",
+					       "image/svg", "image/x-cmu-raster",
+					       "image/x-ico",
+					       "image/x-portable-anymap",
+					       "image/x-portable-bitmap",
+					       "image/x-portable-graymap",
+					       "image/x-portable-pixmap",
+					       "image/x-xpixmap",
+					       "image/jpg", "image/pjpeg",
+					       "image/*", NULL };
+
+typedef struct _EMailFormatterImage {
+	GObject parent;
+} EMailFormatterImage;
+
+typedef struct _EMailFormatterImageClass {
+	GObjectClass parent_class;
+} EMailFormatterImageClass;
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterImage,
+	e_mail_formatter_image,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interface_init));
+
+static gboolean
+emfe_image_format (EMailFormatterExtension *extension,
+                   EMailFormatter *formatter,
+                   EMailFormatterContext *context,
+                   EMailPart *part,
+                   CamelStream *stream,
+                   GCancellable *cancellable)
+{
+	gchar *content;
+	CamelDataWrapper *dw;
+	GByteArray *ba;
+	CamelStream *raw_content;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return FALSE;
+
+	dw = camel_medium_get_content (CAMEL_MEDIUM (part->part));
+	g_return_val_if_fail (dw, FALSE);
+
+	raw_content = camel_stream_mem_new ();
+	camel_data_wrapper_decode_to_stream_sync (dw, raw_content, cancellable, NULL);
+	ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (raw_content));
+
+	if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
+
+		if (!e_mail_formatter_get_animate_images (formatter)) {
+
+			gchar *buff;
+			gsize len;
+
+			e_mail_part_animation_extract_frame (ba, &buff, &len);
+
+			camel_stream_write (stream, buff, len, cancellable, NULL);
+
+			g_free (buff);
+
+		} else {
+
+			camel_stream_write (
+				stream, (gchar *) ba->data,
+				ba->len, cancellable, NULL);
+		}
+
+	} else {
+
+		gchar *buffer;
+
+		if (!e_mail_formatter_get_animate_images (formatter)) {
+
+			gchar *buff;
+			gsize len;
+
+			e_mail_part_animation_extract_frame (ba, &buff, &len);
+
+			content = g_base64_encode ((guchar *) buff, len);
+			g_free (buff);
+
+		} else {
+			content = g_base64_encode ((guchar *) ba->data, ba->len);
+		}
+
+		/* The image is already base64-encrypted so we can directly
+		 * paste it to the output */
+		buffer = g_strdup_printf (
+			"<img src=\"data:%s;base64,%s\" style=\"max-width: 100%%;\" />",
+			part->mime_type ? part->mime_type : "image/*", content);
+
+		camel_stream_write_string (stream, buffer, cancellable, NULL);
+		g_free (buffer);
+		g_free (content);
+	}
+
+	g_object_unref (raw_content);
+
+	return TRUE;
+}
+
+static const gchar *
+emfe_image_get_display_name (EMailFormatterExtension *extension)
+{
+	return _("Regular Image");
+}
+
+static const gchar *
+emfe_image_get_description (EMailFormatterExtension *extension)
+{
+	return _("Display part as an image");
+}
+
+static const gchar **
+emfe_image_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_image_class_init (EMailFormatterImageClass *klass)
+{
+	e_mail_formatter_image_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_image_format;
+	iface->get_display_name = emfe_image_get_display_name;
+	iface->get_description = emfe_image_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_image_mime_types;
+}
+
+static void
+e_mail_formatter_image_init (EMailFormatterImage *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-message-rfc822.c b/em-format/e-mail-formatter-message-rfc822.c
new file mode 100644
index 0000000..558579b
--- /dev/null
+++ b/em-format/e-mail-formatter-message-rfc822.c
@@ -0,0 +1,276 @@
+/*
+ * e-mail-formatter-message-rfc822.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+#include <glib-object.h>
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-part-list.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+static const gchar* formatter_mime_types[] = { "message/rfc822",
+					       "application/vnd.evolution.rfc822.end",
+					       NULL };
+
+typedef struct _EMailFormatterMessageRFC822 {
+	GObject parent;
+} EMailFormatterMessageRFC822;
+
+typedef struct _EMailFormatterMessageRFC822Class {
+	GObjectClass parent_class;
+} EMailFormatterMessageRFC822Class;
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterMessageRFC822,
+	e_mail_formatter_message_rfc822,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interface_init));
+
+static gboolean
+emfe_message_rfc822_format (EMailFormatterExtension *extension,
+                            EMailFormatter *formatter,
+                            EMailFormatterContext *context,
+                            EMailPart *part,
+                            CamelStream *stream,
+                            GCancellable *cancellable)
+{
+	if (g_cancellable_is_cancelled (cancellable))
+		return FALSE;
+
+	if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
+		GSList *iter;
+		gchar *header, *end;
+
+		header = e_mail_formatter_get_html_header (formatter);
+		camel_stream_write_string (stream, header, cancellable, NULL);
+		g_free (header);
+
+		/* Print content of the message normally */
+		context->mode = E_MAIL_FORMATTER_MODE_NORMAL;
+
+		iter = e_mail_part_list_get_iter (context->parts, part->id);
+
+		end = g_strconcat (part->id, ".end", NULL);
+		for (iter = iter->next; iter; iter = g_slist_next (iter)) {
+			EMailPart * p = iter->data;
+			if (!p)
+				continue;
+
+			/* Check for nested rfc822 messages */
+			if (g_str_has_suffix (p->id, ".rfc822")) {
+				gchar *sub_end = g_strconcat (p->id, ".end", NULL);
+
+				while (iter) {
+					p = iter->data;
+					if (!p) {
+						iter = iter->next;
+						continue;
+					}
+
+					if (g_strcmp0 (p->id, sub_end) == 0) {
+						break;
+					}
+
+					iter = iter->next;
+				}
+				g_free (sub_end);
+				continue;
+			}
+			if ((g_strcmp0 (p->id, end) == 0))
+				break;
+
+			if (p->is_hidden)
+				continue;
+
+			e_mail_formatter_format_as (
+				formatter, context, p,
+				stream, NULL, cancellable);
+
+		}
+
+		g_free (end);
+
+		context->mode = E_MAIL_FORMATTER_MODE_RAW;
+
+		camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
+
+	} else if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
+
+		GSList *iter;
+		gchar *end;
+
+		/* Part is EMailPartAttachment */
+		iter = e_mail_part_list_get_iter (context->parts, part->id);
+		iter = g_slist_next (iter);
+
+		if (!iter || !iter->next || !iter->data)
+			return FALSE;
+
+		part = iter->data;
+		end = g_strconcat (part->id, ".end", NULL);
+
+		for (iter = iter->next; iter; iter = g_slist_next (iter)) {
+			EMailPart * p = iter->data;
+			if (!p)
+				continue;
+
+			/* Skip attachment bar */
+			if (g_str_has_suffix (part->id, ".attachment-bar"))
+				continue;
+
+			/* Check for nested rfc822 messages */
+			if (g_str_has_suffix (p->id, ".rfc822")) {
+				gchar *sub_end = g_strconcat (p->id, ".end", NULL);
+
+				while (iter) {
+					p = iter->data;
+					if (!p) {
+						iter = iter->next;
+						continue;
+					}
+
+					if (g_strcmp0 (p->id, sub_end) == 0) {
+						break;
+					}
+
+					iter = iter->next;
+				}
+				g_free (sub_end);
+				continue;
+			}
+
+			if ((g_strcmp0 (p->id, end) == 0))
+				break;
+
+			if (p->is_hidden)
+				continue;
+
+			e_mail_formatter_format_as (
+				formatter, context, p,
+				stream, NULL, cancellable);
+		}
+
+		g_free (end);
+
+	} else {
+		gchar *str;
+		gchar *uri;
+
+		EMailPart *p;
+		GSList *iter;
+
+		iter = e_mail_part_list_get_iter (context->parts, part->id);
+		if (!iter || !iter->next)
+			return FALSE;
+
+		p = iter->data;
+
+		uri = e_mail_part_build_uri (context->folder, context->message_uid,
+			"part_id", G_TYPE_STRING, p->id,
+			"mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+			"headers_collapsable", G_TYPE_INT, 0,
+			NULL);
+
+		str = g_strdup_printf (
+			"<div class=\"part-container\" style=\"border-color: #%06x; "
+			"background-color: #%06x;\">\n"
+			"<iframe width=\"100%%\" height=\"10\""
+			" id=\"%s.iframe\" "
+			" frameborder=\"0\" src=\"%s\" name=\"%s\"></iframe>"
+			"</div>",
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_BODY)),
+			part->id, uri, part->id);
+
+		camel_stream_write_string (stream, str, cancellable, NULL);
+
+		g_free (str);
+		g_free (uri);
+	}
+
+	return TRUE;
+}
+
+static const gchar *
+emfe_message_rfc822_get_display_name (EMailFormatterExtension *extension)
+{
+	return _("RFC822 message");
+}
+
+static const gchar *
+emfe_message_rfc822_get_description (EMailFormatterExtension *extension)
+{
+	return _("Format part as an RFC822 message");
+}
+
+static const gchar **
+emfe_message_rfc822_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_message_rfc822_class_init (EMailFormatterMessageRFC822Class *klass)
+{
+	e_mail_formatter_message_rfc822_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_message_rfc822_format;
+	iface->get_display_name = emfe_message_rfc822_get_display_name;
+	iface->get_description = emfe_message_rfc822_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_message_rfc822_mime_types;
+}
+
+static void
+e_mail_formatter_message_rfc822_init (EMailFormatterMessageRFC822 *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-print-headers.c b/em-format/e-mail-formatter-print-headers.c
new file mode 100644
index 0000000..86fc85b
--- /dev/null
+++ b/em-format/e-mail-formatter-print-headers.c
@@ -0,0 +1,258 @@
+/*
+ * e-mail-formatter-print-headers.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-formatter-utils.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <libemail-engine/e-mail-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailFormatterPrintHeaders {
+	GObject parent;
+} EMailFormatterPrintHeaders;
+
+typedef struct _EMailFormatterPrintHeadersClass {
+	GObjectClass parent_class;
+} EMailFormatterPrintHeadersClass;
+
+static const gchar *formatter_mime_types[] = { "application/vnd.evolution.headers", NULL };
+
+static void e_mail_formatter_print_formatter_extension_interface_init
+					(EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_print_mail_extension_interface_init
+					(EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterPrintHeaders,
+	e_mail_formatter_print_headers,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_print_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_print_formatter_extension_interface_init))
+
+static gboolean
+emfpe_headers_format (EMailFormatterExtension *extension,
+                      EMailFormatter *formatter,
+                      EMailFormatterContext *context,
+                      EMailPart *part,
+                      CamelStream *stream,
+                      GCancellable *cancellable)
+{
+	struct _camel_header_raw raw_header;
+	GString *str, *tmp;
+	gchar *subject;
+	const gchar *buf;
+	GSList *parts_iter;
+	GList *iter;
+	gint attachments_count;
+	gchar *part_id_prefix;
+	const GQueue *headers;
+
+	buf = camel_medium_get_header (CAMEL_MEDIUM (part->part), "subject");
+	subject = camel_header_decode_string (buf, "UTF-8");
+	str = g_string_new ("");
+	g_string_append_printf (str, "<h1>%s</h1>\n", subject);
+	g_free (subject);
+
+	g_string_append (
+		str,
+		"<table border=\"0\" cellspacing=\"5\" "
+		"cellpadding=\"0\" class=\"printing-header\">\n");
+
+	headers = e_mail_formatter_get_headers (formatter);
+	for (iter = headers->head; iter; iter = iter->next) {
+
+		EMailFormatterHeader *header = iter->data;
+		raw_header.name = header->name;
+
+		/* Skip 'Subject' header, it's already displayed. */
+		if (g_ascii_strncasecmp (header->name, "Subject", 7) == 0)
+			continue;
+
+		if (header->value && *header->value) {
+			raw_header.value = header->value;
+			e_mail_formatter_format_header (formatter, str,
+				CAMEL_MEDIUM (part->part), &raw_header,
+				header->flags | E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS,
+				"UTF-8");
+		} else {
+			raw_header.value = g_strdup (camel_medium_get_header (
+				CAMEL_MEDIUM (context->message), header->name));
+
+			if (raw_header.value && *raw_header.value) {
+				e_mail_formatter_format_header (formatter, str,
+					CAMEL_MEDIUM (part->part), &raw_header,
+					header->flags | E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS,
+					"UTF-8");
+			}
+
+			if (raw_header.value)
+				g_free (raw_header.value);
+		}
+	}
+
+        /* Get prefix of this PURI */
+	part_id_prefix = g_strndup (part->id, g_strrstr (part->id, ".") - part->id);
+
+	/* Add encryption/signature header */
+	raw_header.name = _("Security");
+	tmp = g_string_new ("");
+	/* Find first secured part. */
+	for (parts_iter = context->parts; parts_iter; parts_iter = parts_iter->next) {
+
+		EMailPart *mail_part = parts_iter->data;
+		if (mail_part == NULL)
+			continue;
+
+		if (mail_part->validity_type == 0)
+			continue;
+
+		if (!g_str_has_prefix (mail_part->id, part_id_prefix))
+			continue;
+
+		if ((mail_part->validity_type & E_MAIL_PART_VALIDITY_PGP) &&
+		    (mail_part->validity_type & E_MAIL_PART_VALIDITY_SIGNED)) {
+			g_string_append (tmp, _("GPG signed"));
+		}
+		if ((mail_part->validity_type & E_MAIL_PART_VALIDITY_PGP) &&
+		    (mail_part->validity_type & E_MAIL_PART_VALIDITY_ENCRYPTED)) {
+			if (tmp->len > 0) g_string_append (tmp, ", ");
+			g_string_append (tmp, _("GPG encrpyted"));
+		}
+		if ((mail_part->validity_type & E_MAIL_PART_VALIDITY_SMIME) &&
+		    (mail_part->validity_type & E_MAIL_PART_VALIDITY_SIGNED)) {
+
+			if (tmp->len > 0) g_string_append (tmp, ", ");
+			g_string_append (tmp, _("S/MIME signed"));
+		}
+		if ((mail_part->validity_type & E_MAIL_PART_VALIDITY_SMIME) &&
+		    (mail_part->validity_type & E_MAIL_PART_VALIDITY_ENCRYPTED)) {
+
+			if (tmp->len > 0) g_string_append (tmp, ", ");
+			g_string_append (tmp, _("S/MIME encrpyted"));
+		}
+
+		break;
+	}
+
+	if (tmp->len > 0) {
+		raw_header.value = tmp->str;
+		e_mail_formatter_format_header (
+			formatter, str, CAMEL_MEDIUM (part->part), &raw_header,
+			E_MAIL_FORMATTER_HEADER_FLAG_BOLD |
+			E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS, "UTF-8");
+	}
+	g_string_free (tmp, TRUE);
+
+	/* Count attachments and display the number as a header */
+	attachments_count = 0;
+
+	for (parts_iter = context->parts; parts_iter; parts_iter = parts_iter->next) {
+
+		EMailPart *mail_part = parts_iter->data;
+		if (!mail_part)
+			continue;
+
+		if (!g_str_has_prefix (mail_part->id, part_id_prefix))
+			continue;
+
+		if (mail_part->is_attachment && !mail_part->cid &&
+		    !mail_part->is_hidden) {
+			attachments_count++;
+		}
+	}
+
+	if (attachments_count > 0) {
+		raw_header.name = _("Attachments");
+		raw_header.value = g_strdup_printf ("%d", attachments_count);
+		e_mail_formatter_format_header (
+			formatter, str, CAMEL_MEDIUM (part->part), &raw_header,
+			E_MAIL_FORMATTER_HEADER_FLAG_BOLD |
+			E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS, "UTF-8");
+		g_free (raw_header.value);
+	}
+
+	g_string_append (str, "</table>");
+
+	camel_stream_write_string (stream, str->str, cancellable, NULL);
+	g_string_free (str, TRUE);
+	g_free (part_id_prefix);
+
+	return TRUE;
+}
+
+static const gchar *
+emfpe_headers_get_display_name (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar *
+emfpe_headers_get_description (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar **
+emfpe_headers_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_print_headers_class_init (EMailFormatterPrintHeadersClass *klass)
+{
+	e_mail_formatter_print_headers_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_print_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfpe_headers_format;
+	iface->get_display_name = emfpe_headers_get_display_name;
+	iface->get_description = emfpe_headers_get_description;
+}
+
+static void
+e_mail_formatter_print_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfpe_headers_mime_types;
+}
+
+static void
+e_mail_formatter_print_headers_init (EMailFormatterPrintHeaders *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-print.c b/em-format/e-mail-formatter-print.c
new file mode 100644
index 0000000..a9109a6
--- /dev/null
+++ b/em-format/e-mail-formatter-print.c
@@ -0,0 +1,266 @@
+/*
+ * e-mail-formatter-print.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-formatter-print.h"
+
+#include <camel/camel.h>
+
+#include "e-mail-format-extensions.h"
+#include "e-mail-part-attachment.h"
+#include "e-mail-formatter-extension.h"
+#include "e-mail-formatter-utils.h"
+#include "e-mail-part.h"
+
+#include <gdk/gdk.h>
+#include <glib/gi18n.h>
+
+static gpointer e_mail_formatter_print_parent_class = 0;
+
+static void
+write_attachments_list (EMailFormatter *formatter,
+                        EMailFormatterContext *context,
+                        GSList *attachments,
+                        CamelStream *stream,
+                        GCancellable *cancellable)
+{
+	GString *str;
+	GSList *iter;
+
+	if (!attachments)
+		return;
+
+	str = g_string_new (
+		"<table border=\"0\" cellspacing=\"5\" cellpadding=\"0\" "
+		       "class=\"attachments-list\" >\n");
+	g_string_append_printf (str,
+		"<tr><th colspan=\"2\"><h1>%s</h1></td></tr>\n"
+		"<tr><th>%s</th><th>%s</th></tr>\n",
+		_("Attachments"), _("Name"), _("Size"));
+
+	for (iter = attachments; iter; iter = iter->next) {
+		EMailPartAttachment *part = iter->data;
+		EAttachment *attachment;
+		GFileInfo *fi;
+		gchar *name, *size;
+
+		if (!part)
+			continue;
+
+		attachment = part->attachment;
+		fi = e_attachment_get_file_info (attachment);
+		if (!fi)
+			continue;
+
+		if (e_attachment_get_description (attachment) &&
+                    *e_attachment_get_description (attachment)) {
+			name = g_strdup_printf ("%s (%s)",
+				e_attachment_get_description (attachment),
+				g_file_info_get_display_name (fi));
+		} else {
+			name = g_strdup (g_file_info_get_display_name (fi));
+		}
+
+		size = g_format_size (g_file_info_get_size (fi));
+
+		g_string_append_printf (str, "<tr><td>%s</td><td>%s</td></tr>\n",
+			name, size);
+
+		g_free (name);
+		g_free (size);
+	}
+
+	g_string_append (str, "</table>\n");
+
+	camel_stream_write_string (stream, str->str, cancellable, NULL);
+	g_string_free (str, TRUE);
+}
+
+static void
+mail_formatter_print_run (EMailFormatter *formatter,
+                          EMailFormatterContext *context,
+                          CamelStream *stream,
+                          GCancellable *cancellable)
+{
+	GSList *iter;
+	GSList *attachments;
+
+	context->mode = E_MAIL_FORMATTER_MODE_PRINTING;
+
+	camel_stream_write_string (stream,
+		"<!DOCTYPE HTML>\n<html>\n"
+		"<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\" />\n"
+		"<title>Evolution Mail Display</title>\n"
+		"<link type=\"text/css\" rel=\"stylesheet\" media=\"print\" "
+		      "href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview-print.css\" />\n"
+		"</head>\n"
+		"<body style=\"background: #FFF; color: #000;\">",
+		cancellable, NULL);
+
+	attachments = NULL;
+	for (iter = context->parts; iter; iter = g_slist_next (iter)) {
+
+		EMailPart *part;
+		gboolean ok;
+
+		if (g_cancellable_is_cancelled (cancellable))
+			break;
+
+		part = iter->data;
+		if (!part)
+			continue;
+
+		if (part->is_hidden && !part->is_error) {
+			if (g_str_has_suffix (part->id, ".rfc822")) {
+				iter = e_mail_formatter_find_rfc822_end_iter (iter);
+			}
+
+			continue;
+		}
+
+		if (!part->mime_type)
+			continue;
+
+		if (part->is_attachment) {
+			if (part->cid != NULL)
+				continue;
+
+			attachments = g_slist_append (attachments, part);
+		}
+
+		ok = e_mail_formatter_format_as (
+			formatter, context, part, stream,
+			part->mime_type, cancellable);
+
+		/* If the written part was message/rfc822 then
+		 * jump to the end of the message, because content
+		 * of the whole message has been formatted by
+		 * message_rfc822 formatter */
+		if (ok && g_str_has_suffix (part->id, ".rfc822")) {
+			iter = e_mail_formatter_find_rfc822_end_iter (iter);
+
+			continue;
+		}
+	}
+
+	write_attachments_list (formatter, context, attachments, stream, cancellable);
+
+	camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
+}
+
+static void
+mail_formatter_set_style (EMailFormatter *formatter,
+                          GtkStyle *style,
+                          GtkStateType state)
+{
+	EMailFormatterClass *formatter_class;
+
+	/* White background */
+	GdkColor body_color = { 0, G_MAXUINT16, G_MAXUINT16, G_MAXUINT16 };
+	/* Black text */
+	GdkColor text_color = { 0, 0, 0, 0 };
+
+	g_object_freeze_notify (G_OBJECT (formatter));
+
+	/* Set the other colors */
+	formatter_class = E_MAIL_FORMATTER_CLASS (e_mail_formatter_print_parent_class);
+	formatter_class->set_style (formatter, style, state);
+
+	e_mail_formatter_set_color (
+		formatter, E_MAIL_FORMATTER_COLOR_FRAME, &body_color);
+	e_mail_formatter_set_color (
+		formatter, E_MAIL_FORMATTER_COLOR_CONTENT, &body_color);
+	e_mail_formatter_set_color (
+		formatter, E_MAIL_FORMATTER_COLOR_TEXT, &text_color);
+
+	g_object_thaw_notify (G_OBJECT (formatter));
+}
+
+static void
+e_mail_formatter_print_init (EMailFormatterPrint *formatter)
+{
+
+}
+
+static void
+e_mail_formatter_print_finalize (GObject *object)
+{
+	/* Chain up to parent's finalize() */
+	G_OBJECT_CLASS (e_mail_formatter_print_parent_class)->finalize (object);
+}
+
+static void
+e_mail_formatter_print_class_init (EMailFormatterPrintClass *klass)
+{
+	GObjectClass *object_class;
+	EMailFormatterClass *formatter_class;
+
+	e_mail_formatter_print_parent_class = g_type_class_peek_parent (klass);
+
+	formatter_class = E_MAIL_FORMATTER_CLASS (klass);
+	formatter_class->run = mail_formatter_print_run;
+	formatter_class->set_style = mail_formatter_set_style;
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = e_mail_formatter_print_finalize;
+}
+
+static void
+e_mail_formatter_print_base_init (EMailFormatterPrintClass *klass)
+{
+	e_mail_formatter_print_internal_extensions_load (
+		E_MAIL_EXTENSION_REGISTRY (
+			E_MAIL_FORMATTER_CLASS (klass)->extension_registry));
+
+	E_MAIL_FORMATTER_CLASS (klass)->text_html_flags =
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
+}
+
+EMailFormatter *
+e_mail_formatter_print_new (void)
+{
+	return g_object_new (E_TYPE_MAIL_FORMATTER_PRINT, NULL);
+}
+
+GType
+e_mail_formatter_print_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		const GTypeInfo type_info = {
+			sizeof (EMailFormatterClass),
+			(GBaseInitFunc) e_mail_formatter_print_base_init,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) e_mail_formatter_print_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,	/* class_data */
+			sizeof (EMailFormatterPrint),
+			0,	/* n_preallocs */
+			(GInstanceInitFunc) e_mail_formatter_print_init,
+			NULL	/* value_table */
+		};
+
+		type = g_type_register_static (E_TYPE_MAIL_FORMATTER,
+				"EMailFormatterPrint", &type_info, 0);
+	}
+
+	return type;
+}
+
diff --git a/em-format/e-mail-formatter-print.h b/em-format/e-mail-formatter-print.h
new file mode 100644
index 0000000..1783cc0
--- /dev/null
+++ b/em-format/e-mail-formatter-print.h
@@ -0,0 +1,63 @@
+/*
+ * e-mail-formatter-print.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_PRINT_H_
+#define E_MAIL_FORMATTER_PRINT_H_
+
+#include <em-format/e-mail-formatter.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_FORMATTER_PRINT \
+	(e_mail_formatter_print_get_type ())
+#define E_MAIL_FORMATTER_PRINT(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_FORMATTER_PRINT, EMailFormatterPrint))
+#define E_MAIL_FORMATTER_PRINT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_FORMATTER_PRINT, EMailFormatterPrintClass))
+#define E_IS_MAIL_FORMATTER_PRINT(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_FORMATTER_PRINT))
+#define E_IS_MAIL_FORMATTER_PRINT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_FORMATTER_PRINT))
+#define E_MAIL_FORMATTER_PRINT_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_FORMATTER_PRINT, EMailFormatterPrintClass))
+
+G_BEGIN_DECLS;
+
+typedef struct _EMailFormatterPrint EMailFormatterPrint;
+typedef struct _EMailFormatterPrintClass EMailFormatterPrintClass;
+typedef struct _EMailFormatterPrintContext EMailFormatterPrintContext;
+
+struct _EMailFormatterPrint {
+	EMailFormatter parent;
+};
+
+struct _EMailFormatterPrintClass {
+	EMailFormatterClass parent_class;
+};
+
+GType		e_mail_formatter_print_get_type	(void);
+
+EMailFormatter *	e_mail_formatter_print_new	(void);
+
+G_END_DECLS
+
+#endif /* E_MAIL_FORMATTER_PRINT_H_ */
diff --git a/em-format/e-mail-formatter-quote-attachment.c b/em-format/e-mail-formatter-quote-attachment.c
new file mode 100644
index 0000000..590f23e
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-attachment.c
@@ -0,0 +1,163 @@
+/*
+ * e-mail-formatter-qoute-attachment.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+#include "e-mail-part-attachment.h"
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+#define d(x)
+
+typedef struct _EMailFormatterQuoteAttachment {
+	GObject parent;
+} EMailFormatterQuoteAttachment;
+
+typedef struct _EMailFormatterQuoteAttachmentClass {
+	GObjectClass parent_class;
+} EMailFormatterQuoteAttachmentClass;
+
+static void e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterQuoteAttachment,
+	e_mail_formatter_quote_attachment,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_quote_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_quote_formatter_extension_interface_init)
+)
+
+static const gchar *formatter_mime_types[] = { "application/vnd.evolution.attachment",
+					       NULL };
+
+static gboolean
+emfqe_attachment_format (EMailFormatterExtension *extension,
+                         EMailFormatter *formatter,
+                         EMailFormatterContext *context,
+                         EMailPart *part,
+                         CamelStream *stream,
+                         GCancellable *cancellable)
+{
+	gchar *text, *html;
+	guint32 text_format_flags;
+	EMailPartAttachment *empa;
+	EMailPart *att_part;
+	GSList *iter;
+
+	empa = E_MAIL_PART_ATTACHMENT (part);
+
+	if (!empa->attachment_view_part_id)
+		return FALSE;
+
+	iter = e_mail_part_list_get_iter (
+		context->parts, empa->attachment_view_part_id);
+	if (!iter || !iter->data)
+		return FALSE;
+
+	att_part = iter->data;
+
+	camel_stream_write_string (stream, "<br><br>", cancellable, NULL);
+
+	text_format_flags =
+		e_mail_formatter_get_text_format_flags (formatter);
+	text = e_mail_part_describe (part->part,
+			empa ? empa->snoop_mime_type : part->mime_type);
+
+	html = camel_text_to_html (
+			text,
+			text_format_flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS,
+			0);
+	camel_stream_write_string (stream, html, cancellable, NULL);
+	camel_stream_write_string (stream, "<br>", cancellable, NULL);
+	g_free (html);
+	g_free (text);
+
+	camel_stream_write_string (stream,
+			"<!--+GtkHTML:<DATA class=\"ClueFlow\" "
+			"key=\"orig\" value=\"1\">-->\n"
+			"<blockquote type=cite>\n", cancellable, NULL);
+
+	e_mail_formatter_format_as (
+		formatter, context, att_part, stream, NULL, cancellable);
+
+	camel_stream_write_string (stream,
+			"</blockquote><!--+GtkHTML:"
+			"<DATA class=\"ClueFlow\" clear=\"orig\">-->",
+			cancellable, NULL);
+
+	return TRUE;
+}
+
+static const gchar *
+emfqe_attachment_get_display_name (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar *
+emfqe_attachment_get_description (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar **
+emfqe_attachment_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_quote_attachment_class_init (EMailFormatterQuoteAttachmentClass *klass)
+{
+	e_mail_formatter_quote_attachment_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfqe_attachment_format;
+	iface->get_display_name = emfqe_attachment_get_display_name;
+	iface->get_description = emfqe_attachment_get_description;
+}
+
+static void
+e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfqe_attachment_mime_types;
+}
+
+static void
+e_mail_formatter_quote_attachment_init (EMailFormatterQuoteAttachment *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-quote-headers.c b/em-format/e-mail-formatter-quote-headers.c
new file mode 100644
index 0000000..f1b2b2e
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-headers.c
@@ -0,0 +1,162 @@
+/*
+ * e-mail-formatter-quote-headers.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-formatter-utils.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <libemail-engine/e-mail-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailFormatterQuoteHeaders {
+	GObject parent;
+} EMailFormatterQuoteHeaders;
+
+typedef struct _EMailFormatterQuoteHeadersClass {
+	GObjectClass parent_class;
+} EMailFormatterQuoteHeadersClass;
+
+static const gchar *formatter_mime_types[] = { "application/vnd.evolution.headers", NULL };
+
+static void e_mail_formatter_quote_formatter_extension_interface_init
+					(EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_quote_mail_extension_interface_init
+					(EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterQuoteHeaders,
+	e_mail_formatter_quote_headers,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_quote_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_quote_formatter_extension_interface_init))
+
+static gboolean
+emqfe_headers_format (EMailFormatterExtension *extension,
+                      EMailFormatter *formatter,
+                      EMailFormatterContext *context,
+                      EMailPart *part,
+                      CamelStream *stream,
+                      GCancellable *cancellable)
+{
+	CamelContentType *ct;
+	const gchar *charset;
+	GList *iter;
+	GString *buffer;
+	const GQueue *default_headers;
+
+	if (!part)
+		return FALSE;
+
+	ct = camel_mime_part_get_content_type ((CamelMimePart *) part->part);
+	charset = camel_content_type_param (ct, "charset");
+	charset = camel_iconv_charset_name (charset);
+
+	buffer = g_string_new ("");
+
+        /* dump selected headers */
+	default_headers = e_mail_formatter_get_headers (formatter);
+	for (iter = default_headers->head; iter; iter = iter->next) {
+		struct _camel_header_raw *raw_header;
+		EMailFormatterHeader *h = iter->data;
+		guint32 flags;
+
+		flags = h->flags & ~E_MAIL_FORMATTER_HEADER_FLAG_HTML;
+		flags |= E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE;
+
+		for (raw_header = part->part->headers; raw_header; raw_header = raw_header->next) {
+
+			if (g_strcmp0 (raw_header->name, h->name) == 0) {
+
+				e_mail_formatter_format_header (
+					formatter, buffer, (CamelMedium *) part->part,
+					raw_header, flags, charset);
+
+				g_string_append (buffer, "<br>\n");
+				break;
+			}
+		}
+	}
+	g_string_append (buffer, "<br>\n");
+
+	camel_stream_write_string (stream, buffer->str, cancellable, NULL);
+
+	g_string_free (buffer, TRUE);
+
+	return TRUE;
+}
+
+static const gchar *
+emqfe_headers_get_display_name (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar *
+emqfe_headers_get_description (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar **
+emqfe_headers_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_quote_headers_class_init (EMailFormatterQuoteHeadersClass *klass)
+{
+	e_mail_formatter_quote_headers_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emqfe_headers_format;
+	iface->get_display_name = emqfe_headers_get_display_name;
+	iface->get_description = emqfe_headers_get_description;
+}
+
+static void
+e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emqfe_headers_mime_types;
+}
+
+static void
+e_mail_formatter_quote_headers_init (EMailFormatterQuoteHeaders *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-quote-message-rfc822.c b/em-format/e-mail-formatter-quote-message-rfc822.c
new file mode 100644
index 0000000..8476862
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-message-rfc822.c
@@ -0,0 +1,188 @@
+/*
+ * e-mail-formatter-quote-message-rfc822.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+#include <glib-object.h>
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter-quote.h>
+#include <em-format/e-mail-part-list.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+static const gchar* formatter_mime_types[] = { "message/rfc822",
+					       "application/vnd.evolution.rfc822.end",
+					       NULL };
+
+typedef struct _EMailFormatterQuoteMessageRFC822 {
+	GObject parent;
+} EMailFormatterQuoteMessageRFC822;
+
+typedef struct _EMailFormatterQuoteMessageRFC822Class {
+	GObjectClass parent_class;
+} EMailFormatterQuoteMessageRFC822Class;
+
+static void e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterQuoteMessageRFC822,
+	e_mail_formatter_quote_message_rfc822,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_quote_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_quote_formatter_extension_interface_init));
+
+static gboolean
+emfqe_message_rfc822_format (EMailFormatterExtension *extension,
+                             EMailFormatter *formatter,
+                             EMailFormatterContext *context,
+                             EMailPart *part,
+                             CamelStream *stream,
+                             GCancellable *cancellable)
+{
+	GSList *iter;
+	gchar *header, *end;
+	EMailFormatterQuoteContext *qc = (EMailFormatterQuoteContext *) context;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return FALSE;
+
+	header = e_mail_formatter_get_html_header (formatter);
+	camel_stream_write_string (stream, header, cancellable, NULL);
+	g_free (header);
+
+	iter = e_mail_part_list_get_iter (context->parts, part->id);
+
+	end = g_strconcat (part->id, ".end", NULL);
+	for (iter = iter->next; iter; iter = iter->next) {
+		EMailPart * p = iter->data;
+		if (!p)
+			continue;
+
+		/* Skip attachment bar */
+		if (g_str_has_suffix (p->id, ".attachment-bar"))
+			continue;
+
+		if (g_str_has_suffix (p->id, ".headers.")) {
+			if (qc->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS) {
+				e_mail_formatter_format_as (
+					formatter, context, part, stream,
+					"application/vnd.evolution.headers",
+					cancellable);
+			}
+
+			continue;
+		}
+
+		/* Check for nested rfc822 messages */
+		if (g_str_has_suffix (p->id, ".rfc822")) {
+			gchar *sub_end = g_strconcat (p->id, ".end", NULL);
+
+			while (iter) {
+				p = iter->data;
+				if (!p) {
+					iter = iter->next;
+					continue;
+				}
+
+				if (g_strcmp0 (p->id, sub_end) == 0) {
+					break;
+				}
+
+				iter = iter->next;
+			}
+			g_free (sub_end);
+			continue;
+		}
+		if ((g_strcmp0 (p->id, end) == 0))
+			break;
+
+		if (p->is_hidden)
+			continue;
+
+		e_mail_formatter_format_as (
+			formatter, context, p,
+			stream, NULL, cancellable);
+
+	}
+
+	g_free (end);
+
+	camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
+
+	return TRUE;
+}
+
+static const gchar *
+emfqe_message_rfc822_get_display_name (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar *
+emfqe_message_rfc822_get_description (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar **
+emfqe_message_rfc822_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_quote_message_rfc822_class_init (EMailFormatterQuoteMessageRFC822Class *klass)
+{
+	e_mail_formatter_quote_message_rfc822_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfqe_message_rfc822_format;
+	iface->get_display_name = emfqe_message_rfc822_get_display_name;
+	iface->get_description = emfqe_message_rfc822_get_description;
+}
+
+static void
+e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfqe_message_rfc822_mime_types;
+}
+
+static void
+e_mail_formatter_quote_message_rfc822_init (EMailFormatterQuoteMessageRFC822 *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-quote-text-enriched.c b/em-format/e-mail-formatter-quote-text-enriched.c
new file mode 100644
index 0000000..e48154e
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-text-enriched.c
@@ -0,0 +1,141 @@
+/*
+ * e-mail-formatter-quote-text-enriched.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+static const gchar *formatter_mime_types[] = { "text/enriched",
+					       "text/richtext",
+					       NULL };
+
+typedef struct _EMailFormatterQuoteTextEnriched {
+	GObject parent;
+} EMailFormatterQuoteTextEnriched;
+
+typedef struct _EMailFormatterQuoteTextEnrichedClass {
+	GObjectClass parent_class;
+} EMailFormatterQuoteTextEnrichedClass;
+
+static void e_mail_formatter_quote_formatter_extension_interace_init
+					(EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_quote_mail_extension_interface_init
+					(EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterQuoteTextEnriched,
+	e_mail_formatter_quote_text_enriched,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_quote_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_quote_formatter_extension_interace_init));
+
+static gboolean
+emqfe_text_enriched_format (EMailFormatterExtension *extension,
+                            EMailFormatter *formatter,
+                            EMailFormatterContext *context,
+                            EMailPart *part,
+                            CamelStream *stream,
+                            GCancellable *cancellable)
+{
+	CamelStream *filtered_stream;
+	CamelMimeFilter *enriched;
+	guint32 camel_flags = 0;
+
+	if (g_strcmp0 (part->mime_type, "text/richtext") == 0) {
+		camel_flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT;
+		camel_stream_write_string (
+			stream, "\n<!-- text/richtext -->\n",
+			cancellable, NULL);
+	} else {
+		camel_stream_write_string (
+			stream, "\n<!-- text/enriched -->\n",
+			cancellable, NULL);
+	}
+
+	enriched = camel_mime_filter_enriched_new (camel_flags);
+	filtered_stream = camel_stream_filter_new (stream);
+	camel_stream_filter_add (
+		CAMEL_STREAM_FILTER (filtered_stream), enriched);
+	g_object_unref (enriched);
+
+	camel_stream_write_string (stream, "<br><hr><br>", cancellable, NULL);
+	e_mail_formatter_format_text (formatter, part, filtered_stream, cancellable);
+	camel_stream_flush (filtered_stream, cancellable, NULL);
+	g_object_unref (filtered_stream);
+
+	return TRUE;
+}
+
+static const gchar *
+emqfe_text_enriched_get_display_name (EMailFormatterExtension *extension)
+{
+	return _("Richtext");
+}
+
+static const gchar *
+emqfe_text_enriched_get_description (EMailFormatterExtension *extension)
+{
+	return _("Display part as enriched text");
+}
+
+static const gchar **
+emqfe_text_enriched_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_quote_text_enriched_class_init (EMailFormatterQuoteTextEnrichedClass *klass)
+{
+	e_mail_formatter_quote_text_enriched_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_quote_formatter_extension_interace_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emqfe_text_enriched_format;
+	iface->get_display_name = emqfe_text_enriched_get_display_name;
+	iface->get_description = emqfe_text_enriched_get_description;
+}
+
+static void
+e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emqfe_text_enriched_mime_types;
+}
+
+static void
+e_mail_formatter_quote_text_enriched_init (EMailFormatterQuoteTextEnriched *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-quote-text-html.c b/em-format/e-mail-formatter-quote-text-html.c
new file mode 100644
index 0000000..d4ef287
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-text-html.c
@@ -0,0 +1,143 @@
+/*
+ * e-mail-formatter-quote-text-html.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter-quote.h>
+#include <em-format/e-mail-stripsig-filter.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+#include <string.h>
+
+static const gchar *formatter_mime_types[] = { "text/html", NULL };
+
+typedef struct _EMailFormatterQuoteTextHTML {
+	GObject parent;
+} EMailFormatterQuoteTextHTML;
+
+typedef struct _EMailFormatterQuoteTextHTMLClass {
+	GObjectClass parent_class;
+} EMailFormatterQuoteTextHTMLClass;
+
+static void e_mail_formatter_quote_formatter_extension_interface_init
+					(EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_quote_mail_extension_interface_init
+					(EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterQuoteTextHTML,
+	e_mail_formatter_quote_text_html,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_quote_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_quote_formatter_extension_interface_init));
+
+static gboolean
+emqfe_text_html_format (EMailFormatterExtension *extension,
+                        EMailFormatter *formatter,
+                        EMailFormatterContext *context,
+                        EMailPart *part,
+                        CamelStream *stream,
+                        GCancellable *cancellable)
+{
+	EMailFormatterQuoteContext *qf_context;
+
+	qf_context = (EMailFormatterQuoteContext *) context;
+
+	camel_stream_write_string (
+		stream, "\n<!-- text/html -->\n", cancellable, NULL);
+
+	if ((qf_context->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG) == 0) {
+		CamelMimeFilter *sig_strip;
+		CamelStream *filtered_stream;
+
+		filtered_stream = camel_stream_filter_new (stream);
+
+		sig_strip = e_mail_stripsig_filter_new (FALSE);
+		camel_stream_filter_add (
+			CAMEL_STREAM_FILTER (filtered_stream), sig_strip);
+		g_object_unref (sig_strip);
+
+		e_mail_formatter_format_text (
+			formatter, part, filtered_stream, cancellable);
+		camel_stream_flush (filtered_stream, cancellable, NULL);
+		g_object_unref (filtered_stream);
+	} else {
+		e_mail_formatter_format_text (
+			formatter, part, stream, cancellable);
+	}
+
+	return TRUE;
+}
+
+static const gchar *
+emqfe_text_html_get_display_name (EMailFormatterExtension *extension)
+{
+	return _("HTML");
+}
+
+static const gchar *
+emqfe_text_html_get_description (EMailFormatterExtension *extension)
+{
+	return _("Format part as HTML");
+}
+
+static const gchar **
+emqfe_text_html_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_quote_text_html_class_init (EMailFormatterQuoteTextHTMLClass *klass)
+{
+	e_mail_formatter_quote_text_html_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emqfe_text_html_format;
+	iface->get_display_name = emqfe_text_html_get_display_name;
+	iface->get_description = emqfe_text_html_get_description;
+}
+
+static void
+e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emqfe_text_html_mime_types;
+}
+
+static void
+e_mail_formatter_quote_text_html_init (EMailFormatterQuoteTextHTML *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-quote-text-plain.c b/em-format/e-mail-formatter-quote-text-plain.c
new file mode 100644
index 0000000..062e945
--- /dev/null
+++ b/em-format/e-mail-formatter-quote-text-plain.c
@@ -0,0 +1,162 @@
+/*
+ * e-mail-formatter-quote-text-plain.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter-quote.h>
+#include <em-format/e-mail-part-utils.h>
+#include <em-format/e-mail-stripsig-filter.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+static const gchar *formatter_mime_types[] = { "text/plain", NULL };
+
+typedef struct _EMailFormatterQuoteTextPlain {
+	GObject parent;
+} EMailFormatterQuoteTextPlain;
+
+typedef struct _EMailFormatterQuoteTextPlainClass {
+	GObjectClass parent_class;
+} EMailFormatterQuoteTextPlainClass;
+
+static void e_mail_formatter_quote_formatter_extension_interface_init
+					(EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_quote_mail_extension_interface_init
+					(EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterQuoteTextPlain,
+	e_mail_formatter_quote_text_plain,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_quote_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_quote_formatter_extension_interface_init));
+
+static gboolean
+emqfe_text_plain_format (EMailFormatterExtension *extension,
+                         EMailFormatter *formatter,
+                         EMailFormatterContext *context,
+                         EMailPart *part,
+                         CamelStream *stream,
+                         GCancellable *cancellable)
+{
+	CamelStream *filtered_stream;
+	CamelMimeFilter *html_filter;
+	CamelMimeFilter *sig_strip;
+	CamelContentType *type;
+	EMailFormatterQuoteContext *qf_context;
+	const gchar *format;
+	guint32 rgb = 0x737373, text_flags;
+
+	if (!part->part)
+		return FALSE;
+
+	qf_context = (EMailFormatterQuoteContext *) context;
+
+	text_flags = CAMEL_MIME_FILTER_TOHTML_PRE |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
+
+	if (e_mail_formatter_get_mark_citations (formatter)) {
+		text_flags |= CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+	}
+
+	/* Check for RFC 2646 flowed text. */
+	type = camel_mime_part_get_content_type (part->part);
+	if (camel_content_type_is(type, "text", "plain")
+	    && (format = camel_content_type_param(type, "format"))
+	    && !g_ascii_strcasecmp(format, "flowed"))
+		text_flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;
+
+	filtered_stream = camel_stream_filter_new (stream);
+
+	if ((qf_context->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG) == 0) {
+		sig_strip = e_mail_stripsig_filter_new (TRUE);
+		camel_stream_filter_add (
+			CAMEL_STREAM_FILTER (filtered_stream), sig_strip);
+		g_object_unref (sig_strip);
+	}
+
+	html_filter = camel_mime_filter_tohtml_new (text_flags, rgb);
+	camel_stream_filter_add (
+		CAMEL_STREAM_FILTER (filtered_stream), html_filter);
+	g_object_unref (html_filter);
+
+	e_mail_formatter_format_text (
+		formatter, part, filtered_stream, cancellable);
+
+	camel_stream_flush (filtered_stream, cancellable, NULL);
+	g_object_unref (filtered_stream);
+
+	return TRUE;
+}
+
+static const gchar *
+emqfe_text_plain_get_display_name (EMailFormatterExtension *extension)
+{
+	return _("Plain Text");
+}
+
+static const gchar *
+emqfe_text_plain_get_description (EMailFormatterExtension *extension)
+{
+	return _("Format part as plain text");
+}
+
+static const gchar **
+emqfe_text_plain_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_quote_text_plain_class_init (EMailFormatterQuoteTextPlainClass *klass)
+{
+	e_mail_formatter_quote_text_plain_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_quote_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emqfe_text_plain_format;
+	iface->get_display_name = emqfe_text_plain_get_display_name;
+	iface->get_description = emqfe_text_plain_get_description;
+}
+
+static void
+e_mail_formatter_quote_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emqfe_text_plain_mime_types;
+}
+
+static void
+e_mail_formatter_quote_text_plain_init (EMailFormatterQuoteTextPlain *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-quote.c b/em-format/e-mail-formatter-quote.c
new file mode 100644
index 0000000..e4a221e
--- /dev/null
+++ b/em-format/e-mail-formatter-quote.c
@@ -0,0 +1,224 @@
+/*
+ * e-mail-formatter-quote.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-formatter-quote.h"
+
+#include <camel/camel.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-format-extensions.h"
+#include "e-mail-part.h"
+#include "e-mail-part-attachment.h"
+#include "e-mail-part-utils.h"
+
+#include <libebackend/libebackend.h>
+#include <gdk/gdk.h>
+#include <glib/gi18n.h>
+
+struct _EMailFormatterQuotePrivate {
+	gchar *credits;
+	EMailFormatterQuoteFlags flags;
+};
+
+#define E_MAIL_FORMATTER_QUOTE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_MAIL_FORMATTER_QUOTE, EMailFormatterQuotePrivate))
+
+static gpointer e_mail_formatter_quote_parent_class = 0;
+
+static EMailFormatterContext *
+mail_formatter_quote_create_context (EMailFormatter *formatter)
+{
+	return g_malloc0 (sizeof (EMailFormatterQuoteContext));
+}
+
+static void
+mail_formatter_quote_free_context (EMailFormatter *formatter,
+                                   EMailFormatterContext *context)
+{
+	g_free ((EMailFormatterQuoteContext *) context);
+}
+
+static void
+mail_formatter_quote_run (EMailFormatter *formatter,
+                          EMailFormatterContext *context,
+                          CamelStream *stream,
+                          GCancellable *cancellable)
+{
+	EMailFormatterQuote *qf;
+	EMailFormatterQuoteContext *qf_context;
+	GSettings *settings;
+	GSList *iter;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	qf = E_MAIL_FORMATTER_QUOTE (formatter);
+
+	qf_context = (EMailFormatterQuoteContext *) context;
+	qf_context->qf_flags = qf->priv->flags;
+
+	g_seekable_seek (
+		G_SEEKABLE (stream),
+		0, G_SEEK_SET, NULL, NULL);
+
+	settings = g_settings_new ("org.gnome.evolution.mail");
+	if (g_settings_get_boolean (
+		settings, "composer-top-signature"))
+		camel_stream_write_string (
+			stream, "<br>\n", cancellable, NULL);
+	g_object_unref (settings);
+
+	if (qf->priv->credits && *qf->priv->credits) {
+		gchar *credits = g_strdup_printf ("%s<br/>", qf->priv->credits);
+		camel_stream_write_string (stream, credits, cancellable, NULL);
+		g_free (credits);
+	} else {
+		camel_stream_write_string (stream, "<br/>", cancellable, NULL);
+	}
+
+	if (qf->priv->flags & E_MAIL_FORMATTER_QUOTE_FLAG_CITE) {
+		camel_stream_write_string (stream,
+			"<!--+GtkHTML:<DATA class=\"ClueFlow\" "
+			"key=\"orig\" value=\"1\">-->\n"
+			"<blockquote type=cite>\n", cancellable, NULL);
+	}
+
+	for (iter = context->parts; iter; iter = iter->next) {
+		EMailPart *part = iter->data;
+
+		if (!part)
+			continue;
+
+		if (g_str_has_suffix (part->id, ".rfc822")) {
+			gchar *end = g_strconcat (part->id, ".end", NULL);
+
+			while (iter) {
+				EMailPart *p = iter->data;
+				if (!p) {
+					iter = iter->next;
+					continue;
+				}
+
+				if (g_strcmp0 (p->id, end) == 0)
+					break;
+
+				iter = iter->next;
+			}
+			g_free (end);
+			continue;
+		}
+
+		if (part->is_hidden)
+			continue;
+
+		e_mail_formatter_format_as (
+			formatter, context, part, stream,
+			part->mime_type, cancellable);
+	}
+
+	if (qf->priv->flags & E_MAIL_FORMATTER_QUOTE_FLAG_CITE) {
+		camel_stream_write_string (
+			stream, "</blockquote><!--+GtkHTML:"
+			"<DATA class=\"ClueFlow\" clear=\"orig\">-->",
+			cancellable, NULL);
+	}
+}
+
+static void
+e_mail_formatter_quote_init (EMailFormatterQuote *formatter)
+{
+	formatter->priv = E_MAIL_FORMATTER_QUOTE_GET_PRIVATE (formatter);
+}
+
+static void
+e_mail_formatter_quote_finalize (GObject *object)
+{
+	/* Chain up to parent's finalize() */
+	G_OBJECT_CLASS (e_mail_formatter_quote_parent_class)->finalize (object);
+}
+
+static void
+e_mail_formatter_quote_base_init (EMailFormatterQuoteClass *klass)
+{
+	e_mail_formatter_quote_internal_extensions_load (
+		E_MAIL_EXTENSION_REGISTRY (
+			E_MAIL_FORMATTER_CLASS (klass)->extension_registry));
+
+	E_MAIL_FORMATTER_CLASS (klass)->text_html_flags =
+		CAMEL_MIME_FILTER_TOHTML_PRE |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
+}
+
+static void
+e_mail_formatter_quote_class_init (EMailFormatterQuoteClass *klass)
+{
+	GObjectClass *object_class;
+	EMailFormatterClass *formatter_class;
+
+	e_mail_formatter_quote_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (EMailFormatterQuotePrivate));
+
+	formatter_class = E_MAIL_FORMATTER_CLASS (klass);
+	formatter_class->run = mail_formatter_quote_run;
+	formatter_class->create_context = mail_formatter_quote_create_context;
+	formatter_class->free_context = mail_formatter_quote_free_context;
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = e_mail_formatter_quote_finalize;
+}
+
+GType
+e_mail_formatter_quote_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		const GTypeInfo type_info = {
+			sizeof (EMailFormatterClass),
+			(GBaseInitFunc) e_mail_formatter_quote_base_init,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) e_mail_formatter_quote_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,	/* class_data */
+			sizeof (EMailFormatterQuote),
+			0,	/* n_preallocs */
+			(GInstanceInitFunc) e_mail_formatter_quote_init,
+			NULL	/* value_table */
+		};
+
+		type = g_type_register_static (E_TYPE_MAIL_FORMATTER,
+				"EMailFormatterQuote", &type_info, 0);
+	}
+
+	return type;
+}
+
+EMailFormatter *
+e_mail_formatter_quote_new (const gchar *credits,
+                            EMailFormatterQuoteFlags flags)
+{
+	EMailFormatterQuote *formatter;
+	formatter = g_object_new (E_TYPE_MAIL_FORMATTER_QUOTE, NULL);
+
+	formatter->priv->credits = g_strdup (credits);
+	formatter->priv->flags = flags;
+
+	return (EMailFormatter *) formatter;
+}
diff --git a/em-format/e-mail-formatter-quote.h b/em-format/e-mail-formatter-quote.h
new file mode 100644
index 0000000..fa6730b
--- /dev/null
+++ b/em-format/e-mail-formatter-quote.h
@@ -0,0 +1,79 @@
+/*
+ * e-mail-formatter-quote.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_QUOTE_H_
+#define E_MAIL_FORMATTER_QUOTE_H_
+
+#include <em-format/e-mail-formatter.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_FORMATTER_QUOTE \
+	(e_mail_formatter_quote_get_type ())
+#define E_MAIL_FORMATTER_QUOTE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_FORMATTER_QUOTE, EMailFormatterQuote))
+#define E_MAIL_FORMATTER_QUOTE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_FORMATTER_QUOTE, EMailFormatterQuoteClass))
+#define E_IS_MAIL_FORMATTER_QUOTE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_FORMATTER_QUOTE))
+#define E_IS_MAIL_FORMATTER_QUOTE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_FORMATTER_QUOTE))
+#define E_MAIL_FORMATTER_QUOTE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_FORMATTER_QUOTE, EMailFormatterQuoteClass))
+
+G_BEGIN_DECLS;
+
+typedef struct _EMailFormatterQuote EMailFormatterQuote;
+typedef struct _EMailFormatterQuoteClass EMailFormatterQuoteClass;
+typedef struct _EMailFormatterQuotePrivate EMailFormatterQuotePrivate;
+typedef struct _EMailFormatterQuoteContext EMailFormatterQuoteContext;
+
+typedef enum {
+	E_MAIL_FORMATTER_QUOTE_FLAG_CITE	= 1 << 0,
+	E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS	= 1 << 1,
+	E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG	= 1 << 2  /* do not strip signature */
+} EMailFormatterQuoteFlags;
+
+struct _EMailFormatterQuoteContext {
+	EMailFormatterContext parent;
+
+	guint32 qf_flags;
+};
+
+struct _EMailFormatterQuote {
+	EMailFormatter parent;
+
+	EMailFormatterQuotePrivate *priv;
+};
+
+struct _EMailFormatterQuoteClass {
+	EMailFormatterClass parent_class;
+};
+
+GType		e_mail_formatter_quote_get_type	(void);
+
+EMailFormatter *	e_mail_formatter_quote_new	(const gchar *credits,
+						 EMailFormatterQuoteFlags flags);
+
+G_END_DECLS
+
+#endif /* E_MAIL_FORMATTER_QUOTE_H_ */
diff --git a/em-format/e-mail-formatter-secure-button.c b/em-format/e-mail-formatter-secure-button.c
new file mode 100644
index 0000000..05319ef
--- /dev/null
+++ b/em-format/e-mail-formatter-secure-button.c
@@ -0,0 +1,472 @@
+/*
+ * evolution-secure-button.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <e-util/e-util.h>
+
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+#include "certificate-viewer.h"
+#include "e-cert-db.h"
+#endif
+
+#include <camel/camel.h>
+
+typedef struct _EMailFormatterSecureButton {
+	GObject parent;
+} EMailFormatterSecureButton;
+
+typedef struct _EMailFormatterSecureButtonClass {
+	GObjectClass parent_class;
+} EMailFormatterSecureButtonClass;
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterSecureButton,
+	e_mail_formatter_secure_button,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interface_init));
+
+static const gchar *formatter_mime_types[] = { "application/vnd.evolution.widget.secure-button", NULL };
+
+static const struct {
+	const gchar *icon, *shortdesc, *description;
+} smime_sign_table[5] = {
+	{ "stock_signature-bad", N_("Unsigned"), N_("This message is not signed. There is no guarantee that this message is authentic.") },
+	{ "stock_signature-ok", N_("Valid signature"), N_("This message is signed and is valid meaning that it is very likely that this message is authentic.") },
+	{ "stock_signature-bad", N_("Invalid signature"), N_("The signature of this message cannot be verified, it may have been altered in transit.") },
+	{ "stock_signature", N_("Valid signature, but cannot verify sender"), N_("This message is signed with a valid signature, but the sender of the message cannot be verified.") },
+	{ "stock_signature-bad", N_("Signature exists, but need public key"), N_("This message is signed with a signature, but there is no corresponding public key.") },
+
+};
+
+static const struct {
+	const gchar *icon, *shortdesc, *description;
+} smime_encrypt_table[4] = {
+	{ "stock_lock-broken", N_("Unencrypted"), N_("This message is not encrypted. Its content may be viewed in transit across the Internet.") },
+	{ "stock_lock-ok", N_("Encrypted, weak"), N_("This message is encrypted, but with a weak encryption algorithm. It would be difficult, but not impossible for an outsider to view the content of this message in a practical amount of time.") },
+	{ "stock_lock-ok", N_("Encrypted"), N_("This message is encrypted.  It would be difficult for an outsider to view the content of this message.") },
+	{ "stock_lock-ok", N_("Encrypted, strong"), N_("This message is encrypted, with a strong encryption algorithm. It would be very difficult for an outsider to view the content of this message in a practical amount of time.") },
+};
+
+static const GdkRGBA smime_sign_colour[5] = {
+	{ 0 }, { 0.53, 0.73, 0.53, 1 }, { 0.73, 0.53, 0.53, 1 }, { 0.91, 0.82, 0.13, 1 }, { 0 },
+};
+
+static gboolean
+emfe_secure_button_format (EMailFormatterExtension *extension,
+                           EMailFormatter *formatter,
+                           EMailFormatterContext *context,
+                           EMailPart *part,
+                           CamelStream *stream,
+                           GCancellable *cancellable)
+{
+	gchar *str;
+
+	if ((context->mode != E_MAIL_FORMATTER_MODE_NORMAL) &&
+	    (context->mode != E_MAIL_FORMATTER_MODE_RAW))
+		return FALSE;
+
+	str = g_strdup_printf (
+		"<object type=\"application/vnd.evolution.widget.secure-button\" "
+		"height=\"20\" width=\"100%%\" data=\"%s\" id=\"%s\"></object>",
+		part->id, part->id);
+
+	camel_stream_write_string (stream, str, cancellable, NULL);
+
+	g_free (str);
+	return TRUE;
+}
+
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+static void
+viewcert_clicked (GtkWidget *button,
+                  GtkWidget *parent)
+{
+	CamelCipherCertInfo *info = g_object_get_data((GObject *) button, "e-cert-info");
+	ECert *ec = NULL;
+
+	if (info->cert_data)
+		ec = e_cert_new (CERT_DupCertificate (info->cert_data));
+
+	if (ec != NULL) {
+		GtkWidget *w = certificate_viewer_show (ec);
+
+		/* oddly enough certificate_viewer_show doesn't ... */
+		gtk_widget_show (w);
+		g_signal_connect (
+			w, "response",
+			G_CALLBACK (gtk_widget_destroy), NULL);
+
+		if (w && parent)
+			gtk_window_set_transient_for (
+				(GtkWindow *) w, (GtkWindow *) parent);
+
+		g_object_unref (ec);
+	} else {
+		g_warning("can't find certificate for %s <%s>",
+			info->name ? info->name : "",
+			info->email ? info->email : "");
+	}
+}
+#endif
+
+static void
+info_response (GtkWidget *widget,
+               guint button,
+               gpointer user_data)
+{
+	gtk_widget_destroy (widget);
+}
+
+static void
+add_cert_table (GtkWidget *grid,
+                GQueue *certlist,
+                gpointer user_data)
+{
+	GList *head, *link;
+	GtkTable *table;
+	gint n = 0;
+
+	table = (GtkTable *) gtk_table_new (certlist->length, 2, FALSE);
+
+	head = g_queue_peek_head_link (certlist);
+
+	for (link = head; link != NULL; link = g_list_next (link)) {
+		CamelCipherCertInfo *info = link->data;
+		gchar *la = NULL;
+		const gchar *l = NULL;
+
+		if (info->name) {
+			if (info->email && strcmp (info->name, info->email) != 0)
+				l = la = g_strdup_printf("%s <%s>", info->name, info->email);
+			else
+				l = info->name;
+		} else {
+			if (info->email)
+				l = info->email;
+		}
+
+		if (l) {
+			GtkWidget *w;
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+			ECert *ec = NULL;
+#endif
+			w = gtk_label_new (l);
+			gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
+			g_free (la);
+			gtk_table_attach (table, w, 0, 1, n, n + 1, GTK_FILL, GTK_FILL, 3, 3);
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+			w = gtk_button_new_with_mnemonic(_("_View Certificate"));
+			gtk_table_attach (table, w, 1, 2, n, n + 1, 0, 0, 3, 3);
+			g_object_set_data((GObject *)w, "e-cert-info", info);
+			g_signal_connect (
+				w, "clicked",
+				G_CALLBACK (viewcert_clicked), grid);
+
+			if (info->cert_data)
+				ec = e_cert_new (CERT_DupCertificate (info->cert_data));
+
+			if (ec == NULL)
+				gtk_widget_set_sensitive (w, FALSE);
+			else
+				g_object_unref (ec);
+#else
+			w = gtk_label_new (_("This certificate is not viewable"));
+			gtk_table_attach (table, w, 1, 2, n, n + 1, 0, 0, 3, 3);
+#endif
+			n++;
+		}
+	}
+
+	gtk_container_add (GTK_CONTAINER (grid), GTK_WIDGET (table));
+}
+
+static void
+format_cert_infos (GQueue *cert_infos,
+                   GString *output_buffer)
+{
+	GQueue valid = G_QUEUE_INIT;
+	GList *head, *link;
+
+	head = g_queue_peek_head_link (cert_infos);
+
+	/* Make sure we have a valid CamelCipherCertInfo before
+	 * appending anything to the output buffer, so we don't
+	 * end up with "()". */
+	for (link = head; link != NULL; link = g_list_next (link)) {
+		CamelCipherCertInfo *cinfo = link->data;
+
+		if ((cinfo->name != NULL && *cinfo->name != '\0') ||
+		    (cinfo->email != NULL && *cinfo->email != '\0')) {
+			g_queue_push_tail (&valid, cinfo);
+		}
+	}
+
+	if (g_queue_is_empty (&valid))
+		return;
+
+	g_string_append (output_buffer, " (");
+
+	while (!g_queue_is_empty (&valid)) {
+		CamelCipherCertInfo *cinfo;
+
+		cinfo = g_queue_pop_head (&valid);
+
+		if (cinfo->name != NULL && *cinfo->name != '\0') {
+			g_string_append (output_buffer, cinfo->name);
+
+			if (cinfo->email != NULL && *cinfo->email != '\0') {
+				g_string_append (output_buffer, " <");
+				g_string_append (output_buffer, cinfo->email);
+				g_string_append (output_buffer, ">");
+			}
+
+		} else if (cinfo->email != NULL && *cinfo->email != '\0') {
+			g_string_append (output_buffer, cinfo->email);
+		}
+
+		if (!g_queue_is_empty (&valid))
+			g_string_append (output_buffer, ", ");
+	}
+
+	g_string_append_c (output_buffer, ')');
+}
+
+static void
+secure_button_clicked_cb (GtkWidget *widget,
+                          EMailPart *part)
+{
+	GtkBuilder *builder;
+	GtkWidget *grid, *w;
+	GtkWidget *dialog;
+
+	builder = gtk_builder_new ();
+	e_load_ui_builder_definition (builder, "mail-dialogs.ui");
+
+	dialog = e_builder_get_widget(builder, "message_security_dialog");
+
+	grid = e_builder_get_widget(builder, "signature_grid");
+	w = gtk_label_new (_(smime_sign_table[part->validity->sign.status].description));
+	gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
+	gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
+	gtk_container_add (GTK_CONTAINER (grid), w);
+	if (part->validity->sign.description) {
+		GtkTextBuffer *buffer;
+
+		buffer = gtk_text_buffer_new (NULL);
+		gtk_text_buffer_set_text (
+			buffer, part->validity->sign.description,
+			strlen (part->validity->sign.description));
+		w = g_object_new (gtk_scrolled_window_get_type (),
+				 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+				 "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+				 "shadow_type", GTK_SHADOW_IN,
+				 "expand", TRUE,
+				 "child", g_object_new(gtk_text_view_get_type(),
+						       "buffer", buffer,
+						       "cursor_visible", FALSE,
+						       "editable", FALSE,
+						       "width_request", 500,
+						       "height_request", 160,
+						       NULL),
+				 NULL);
+		g_object_unref (buffer);
+
+		gtk_container_add (GTK_CONTAINER (grid), w);
+	}
+
+	if (!g_queue_is_empty (&part->validity->sign.signers))
+		add_cert_table (
+			grid, &part->validity->sign.signers, NULL);
+
+	gtk_widget_show_all (grid);
+
+	grid = e_builder_get_widget(builder, "encryption_grid");
+	w = gtk_label_new (_(smime_encrypt_table[part->validity->encrypt.status].description));
+	gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
+	gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
+	gtk_container_add (GTK_CONTAINER (grid), w);
+	if (part->validity->encrypt.description) {
+		GtkTextBuffer *buffer;
+
+		buffer = gtk_text_buffer_new (NULL);
+		gtk_text_buffer_set_text (
+			buffer, part->validity->encrypt.description,
+			strlen (part->validity->encrypt.description));
+		w = g_object_new (gtk_scrolled_window_get_type (),
+				 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+				 "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+				 "shadow_type", GTK_SHADOW_IN,
+				 "expand", TRUE,
+				 "child", g_object_new(gtk_text_view_get_type(),
+						       "buffer", buffer,
+						       "cursor_visible", FALSE,
+						       "editable", FALSE,
+						       "width_request", 500,
+						       "height_request", 160,
+						       NULL),
+				 NULL);
+		g_object_unref (buffer);
+
+		gtk_container_add (GTK_CONTAINER (grid), w);
+	}
+
+	if (!g_queue_is_empty (&part->validity->encrypt.encrypters))
+		add_cert_table (grid, &part->validity->encrypt.encrypters, NULL);
+
+	gtk_widget_show_all (grid);
+
+	g_object_unref (builder);
+
+	g_signal_connect (
+		dialog, "response",
+		G_CALLBACK (info_response), NULL);
+
+	gtk_widget_show (dialog);
+}
+
+static GtkWidget *
+emfe_secure_button_get_widget (EMailFormatterExtension *extension,
+                               EMailPartList *context,
+                               EMailPart *part,
+                               GHashTable *params)
+{
+	GtkWidget *box, *button, *layout, *widget;
+	const gchar *icon_name;
+	gchar *description;
+	GString *buffer;
+	buffer = g_string_new ("");
+
+	if (part->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
+		const gchar *desc;
+		gint status;
+
+		status = part->validity->sign.status;
+		desc = smime_sign_table[status].shortdesc;
+
+		g_string_append (buffer, gettext (desc));
+
+		format_cert_infos (&part->validity->sign.signers, buffer);
+	}
+
+	if (part->validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
+		const gchar *desc;
+		gint status;
+
+		if (part->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
+			g_string_append (buffer, "\n");
+
+		status = part->validity->encrypt.status;
+		desc = smime_encrypt_table[status].shortdesc;
+		g_string_append (buffer, gettext (desc));
+	}
+
+	description = g_string_free (buffer, FALSE);
+
+	/* FIXME: need to have it based on encryption and signing too */
+	if (part->validity->sign.status != 0)
+		icon_name = smime_sign_table[part->validity->sign.status].icon;
+	else
+		icon_name = smime_encrypt_table[part->validity->encrypt.status].icon;
+
+	box = gtk_event_box_new ();
+	if (part->validity->sign.status != 0)
+		gtk_widget_override_background_color (box, GTK_STATE_FLAG_NORMAL,
+			&smime_sign_colour[part->validity->sign.status]);
+
+	layout = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
+	gtk_container_add (GTK_CONTAINER (box), layout);
+
+	button = gtk_button_new ();
+	gtk_box_pack_start (GTK_BOX (layout), button, FALSE, FALSE, 0);
+	g_signal_connect (button, "clicked",
+		G_CALLBACK (secure_button_clicked_cb), part);
+
+	widget = gtk_image_new_from_icon_name (
+			icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
+	gtk_button_set_image (GTK_BUTTON (button), widget);
+
+	widget = gtk_label_new (description);
+	gtk_box_pack_start (GTK_BOX (layout), widget, FALSE, FALSE, 0);
+
+	gtk_widget_show_all (box);
+
+	g_free (description);
+	return box;
+}
+
+static const gchar *
+emfe_secure_button_get_display_name (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar *
+emfe_secure_button_get_description (EMailFormatterExtension *extension)
+{
+	return NULL;
+}
+
+static const gchar **
+emfe_secure_button_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_secure_button_class_init (EMailFormatterSecureButtonClass *klass)
+{
+	e_mail_formatter_secure_button_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_secure_button_format;
+	iface->get_widget = emfe_secure_button_get_widget;
+	iface->get_display_name = emfe_secure_button_get_display_name;
+	iface->get_description = emfe_secure_button_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_secure_button_mime_types;
+}
+
+static void
+e_mail_formatter_secure_button_init (EMailFormatterSecureButton *extension)
+{
+
+}
diff --git a/em-format/e-mail-formatter-source.c b/em-format/e-mail-formatter-source.c
new file mode 100644
index 0000000..92c3a92
--- /dev/null
+++ b/em-format/e-mail-formatter-source.c
@@ -0,0 +1,178 @@
+/*
+ * evolution-source.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+typedef struct _EMailFormatterSource {
+	GObject parent;
+} EMailFormatterSource;
+
+typedef struct _EMailFormatterSourceClass {
+	GObjectClass parent_class;
+} EMailFormatterSourceClass;
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterSource,
+	e_mail_formatter_source,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interface_init)
+)
+
+static const gchar *formatter_mime_types[] = { "application/vnd.evolution.source", NULL };
+
+static gboolean
+emfe_source_format (EMailFormatterExtension *extension,
+                    EMailFormatter *formatter,
+                    EMailFormatterContext *context,
+                    EMailPart *part,
+                    CamelStream *stream,
+                    GCancellable *cancellable)
+{
+	GString *buffer;
+	CamelStream *filtered_stream;
+	CamelMimeFilter *filter;
+	CamelDataWrapper *dw = (CamelDataWrapper *) part->part;
+
+	filtered_stream = camel_stream_filter_new (stream);
+
+	filter = camel_mime_filter_tohtml_new (
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
+		CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0);
+	camel_stream_filter_add (
+		CAMEL_STREAM_FILTER (filtered_stream), filter);
+	g_object_unref (filter);
+
+	buffer = g_string_new ("");
+
+	if (CAMEL_IS_MIME_MESSAGE (part->part)) {
+		g_string_append_printf (
+			buffer,
+			"<div class=\"part-container\" "
+			"style=\"border: 0; background: #%06x; color: #%06x;\" >",
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_BODY)),
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_TEXT)));
+	} else {
+		g_string_append_printf (
+			buffer,
+			"<div class=\"part-container\" "
+			"style=\"border-color: #%06x; background: #%06x; color: #%06x;\">"
+			"<div class=\"part-container-inner-margin pre\">\n",
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_BODY)),
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_TEXT)));
+	}
+
+	camel_stream_write_string (
+		stream, buffer->str, cancellable, NULL);
+	camel_stream_write_string (
+		stream, "<code class=\"pre\">", cancellable, NULL);
+
+	camel_data_wrapper_write_to_stream_sync (dw, filtered_stream,
+		cancellable, NULL);
+	camel_stream_flush (filtered_stream, cancellable, NULL);
+	g_object_unref (filtered_stream);
+
+	camel_stream_write_string (
+		stream, "</code>", cancellable, NULL);
+
+	g_string_free (buffer, TRUE);
+
+	if (CAMEL_IS_MIME_MESSAGE (part->part)) {
+		camel_stream_write_string (stream, "</div>", cancellable, NULL);
+	} else {
+		camel_stream_write_string (stream, "</div></div>", cancellable, NULL);
+	}
+
+	return TRUE;
+}
+
+static const gchar *
+emfe_source_get_display_name (EMailFormatterExtension *extension)
+{
+	return _("Source");
+}
+
+static const gchar *
+emfe_source_get_description (EMailFormatterExtension *extension)
+{
+	return _("Display source of a MIME part");
+}
+
+static const gchar **
+emfe_source_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_source_class_init (EMailFormatterSourceClass *klass)
+{
+	e_mail_formatter_source_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_source_format;
+	iface->get_display_name = emfe_source_get_display_name;
+	iface->get_description = emfe_source_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_source_mime_types;
+}
+
+static void
+e_mail_formatter_source_init (EMailFormatterSource *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-text-enriched.c b/em-format/e-mail-formatter-text-enriched.c
new file mode 100644
index 0000000..fce7b31
--- /dev/null
+++ b/em-format/e-mail-formatter-text-enriched.c
@@ -0,0 +1,154 @@
+/*
+ * e-mail-formatter-text-enriched.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+static const gchar *formatter_mime_types[] = { "text/enriched",
+					       "text/richtext",
+					       NULL };
+
+typedef struct _EMailFormatterTextEnriched {
+	GObject parent;
+} EMailFormatterTextEnriched;
+
+typedef struct _EMailFormatterTextEnrichedClass {
+	GObjectClass parent_class;
+} EMailFormatterTextEnrichedClass;
+
+static void e_mail_formatter_formatter_extension_interace_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterTextEnriched,
+	e_mail_formatter_text_enriched,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interace_init));
+
+static gboolean
+emfe_text_enriched_format (EMailFormatterExtension *extension,
+                           EMailFormatter *formatter,
+                           EMailFormatterContext *context,
+                           EMailPart *part,
+                           CamelStream *stream,
+                           GCancellable *cancellable)
+{
+	CamelStream *filtered_stream;
+	CamelMimeFilter *enriched;
+	guint32 filter_flags = 0;
+	GString *buffer;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return FALSE;
+
+	if (!g_strcmp0(part->mime_type, "text/richtext")) {
+		filter_flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT;
+	}
+
+	enriched = camel_mime_filter_enriched_new (filter_flags);
+	filtered_stream = camel_stream_filter_new (stream);
+	camel_stream_filter_add (
+		CAMEL_STREAM_FILTER (filtered_stream), enriched);
+	g_object_unref (enriched);
+
+	buffer = g_string_new ("");
+
+	g_string_append_printf (buffer,
+		"<div class=\"part-container\" style=\"border-color: #%06x; "
+		"background-color: #%06x; color: #%06x;\">"
+		"<div class=\"part-container-inner-margin\">\n",
+		e_color_to_value ((GdkColor *)
+			e_mail_formatter_get_color (formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+		e_color_to_value ((GdkColor *)
+			e_mail_formatter_get_color (formatter, E_MAIL_FORMATTER_COLOR_CONTENT)),
+		e_color_to_value ((GdkColor *)
+			e_mail_formatter_get_color (formatter, E_MAIL_FORMATTER_COLOR_TEXT)));
+
+	camel_stream_write_string (stream, buffer->str, cancellable, NULL);
+	g_string_free (buffer, TRUE);
+
+	e_mail_formatter_format_text (
+		formatter, part, filtered_stream, cancellable);
+	camel_stream_flush (filtered_stream, cancellable, NULL);
+	g_object_unref (filtered_stream);
+
+	camel_stream_write_string (stream, "</div></div>", cancellable, NULL);
+
+	return TRUE;
+}
+
+static const gchar *
+emfe_text_enriched_get_display_name (EMailFormatterExtension *extension)
+{
+	return _("Richtext");
+}
+
+static const gchar *
+emfe_text_enriched_get_description (EMailFormatterExtension *extension)
+{
+	return _("Display part as enriched text");
+}
+
+static const gchar **
+emfe_text_enriched_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_text_enriched_class_init (EMailFormatterTextEnrichedClass *klass)
+{
+	e_mail_formatter_text_enriched_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interace_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_text_enriched_format;
+	iface->get_display_name = emfe_text_enriched_get_display_name;
+	iface->get_description = emfe_text_enriched_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_text_enriched_mime_types;
+}
+
+static void
+e_mail_formatter_text_enriched_init (EMailFormatterTextEnriched *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-text-html.c b/em-format/e-mail-formatter-text-html.c
new file mode 100644
index 0000000..28fb264
--- /dev/null
+++ b/em-format/e-mail-formatter-text-html.c
@@ -0,0 +1,376 @@
+/*
+ * e-mail-formatter-text-html.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+#include <ctype.h>
+#include <string.h>
+
+static const gchar *formatter_mime_types[] = { "text/html", NULL };
+
+typedef struct _EMailFormatterTextHTML {
+	GObject parent;
+} EMailFormatterTextHTML;
+
+typedef struct _EMailFormatterTextHTMLClass {
+	GObjectClass parent_class;
+} EMailFormatterTextHTMLClass;
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterTextHTML,
+	e_mail_formatter_text_html,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interface_init));
+
+static gchar *
+get_tag (const gchar *utf8_string,
+         const gchar *tag_name,
+         gchar *opening,
+         gchar *closing)
+{
+	gchar *t;
+	gunichar c;
+	gboolean has_end;
+
+	t = g_utf8_find_prev_char (utf8_string, closing);
+	while (t != opening) {
+
+		c = g_utf8_get_char (t);
+		if (!g_unichar_isspace (c))
+			break;
+	}
+
+	/* Not a pair tag */
+	if (c == '/')
+		return g_strndup (opening, closing - opening + 1);
+
+	t = closing;
+	while (t) {
+		c = g_utf8_get_char (t);
+		if (c == '<')
+			break;
+
+		t = g_utf8_find_next_char (t, NULL);
+	}
+
+	do {
+		c = g_utf8_get_char (t);
+
+		if (c == '/') {
+			has_end = TRUE;
+			break;
+		}
+
+		if (c == '>') {
+			has_end = FALSE;
+			break;
+		}
+
+		t = g_utf8_find_next_char (t, NULL);
+
+	} while (t);
+
+	/* Broken HTML? */
+	if (!has_end)
+		return g_strndup (opening, closing - opening + 1);
+
+	do {
+		c = g_utf8_get_char (t);
+		if ((c != ' ') && (c != '/'))
+			break;
+
+		t = g_utf8_find_next_char (t, NULL);
+	} while (t);
+
+	/* tag_name is always ASCII */
+	if (g_ascii_strncasecmp (t, tag_name, strlen (tag_name)) == 0) {
+
+		closing = g_utf8_strchr (t, -1, '>');
+
+		return g_strndup (opening, closing - opening + 1);
+	}
+
+	/* Broken HTML? */
+	return g_strndup (opening, closing - opening + 1);
+}
+
+static gboolean
+emfe_text_html_format (EMailFormatterExtension *extension,
+                       EMailFormatter *formatter,
+                       EMailFormatterContext *context,
+                       EMailPart *part,
+                       CamelStream *stream,
+                       GCancellable *cancellable)
+{
+	if (g_cancellable_is_cancelled (cancellable))
+		return FALSE;
+
+	if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
+		/* FORMATTER FIXME: Shouldn't we have some extra method for
+		 * BASE64 and QP decoding?? */
+		e_mail_formatter_format_text (formatter, part, stream, cancellable);
+
+	} else if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
+		GString *string;
+		GByteArray *ba;
+		gchar *pos;
+		GList *tags, *iter;
+		gboolean valid;
+		gchar *tag;
+		const gchar *document_end;
+		gint length;
+		gint i;
+		CamelStream *decoded_stream;
+
+		decoded_stream = camel_stream_mem_new ();
+		/* FORMATTER FIXME: See above */
+		e_mail_formatter_format_text (formatter, part, decoded_stream, cancellable);
+		g_seekable_seek (G_SEEKABLE (decoded_stream), 0, G_SEEK_SET, cancellable, NULL);
+
+		ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (decoded_stream));
+		string = g_string_new_len ((gchar *) ba->data, ba->len);
+
+		g_object_unref (decoded_stream);
+
+		tags = NULL;
+		pos = string->str;
+		valid = FALSE;
+
+		if (!g_utf8_validate (string->str, -1, NULL)) {
+			/* FIXME - What do we do if the string is not UTF-8 valid? */
+		}
+
+		do {
+			gchar *tmp;
+			gchar *closing;
+			gchar *opening;
+
+			tmp = g_utf8_find_next_char (pos, NULL);
+			pos = g_utf8_strchr (tmp, -1, '<');
+			if (!pos)
+				break;
+
+			opening = pos;
+			closing = g_utf8_strchr (pos, -1, '>');
+
+			/* Find where the actual tag name begins */
+			tag = g_utf8_find_next_char (pos, NULL);
+			while ((tag = g_utf8_find_next_char (pos, NULL)) != NULL) {
+				gunichar c = g_utf8_get_char (tag);
+				if (!g_unichar_isspace (c))
+					break;
+
+			}
+
+			if (g_ascii_strncasecmp (tag, "style", 5) == 0) {
+				tags = g_list_append (
+					tags,
+					get_tag (string->str, "style", opening, closing));
+			} else if (g_ascii_strncasecmp (tag, "script", 6) == 0) {
+				tags = g_list_append (
+					tags,
+					get_tag (string->str, "script", opening, closing));
+			} else if (g_ascii_strncasecmp (tag, "link", 4) == 0) {
+				tags = g_list_append (
+					tags,
+					get_tag (string->str, "link", opening, closing));
+			} else if (g_ascii_strncasecmp (tag, "body", 4) == 0) {
+				valid = TRUE;
+				break;
+			}
+
+		} while (pos);
+
+		if (tags)
+			printf("\n\n**%s**\n\n", (gchar *) tags->data);
+
+		/* Something's wrong, let's write the entire HTML and hope
+		 * that WebKit can handle it */
+		if (!valid) {
+			EMailFormatterContext c = {
+				.folder = context->folder,
+				.message = context->message,
+				.message_uid = context->message_uid,
+				.parts = context->parts,
+				.flags = context->flags,
+				.mode = E_MAIL_FORMATTER_MODE_RAW,
+			};
+
+			emfe_text_html_format (
+				extension, formatter, &c, part, stream, cancellable);
+			return FALSE;
+		}
+
+		/*	       include the "body" as well -----v */
+		g_string_erase (string, 0, tag - string->str + 4);
+		g_string_prepend (string, "<div ");
+
+		for (iter = tags; iter; iter = iter->next) {
+			g_string_prepend (string, iter->data);
+		}
+
+		g_list_free_full (tags, g_free);
+
+		document_end = NULL;
+		/* We can probably use ASCII functions here */
+		if (g_strrstr (string->str, "</body>")) {
+			document_end = ">ydob/<";
+		}
+
+		if (g_strrstr (string->str, "</html>")) {
+			if (document_end) {
+				document_end = ">lmth/<>ydob/<";
+			} else {
+				document_end = ">lmth/<";
+			}
+		}
+
+		if (document_end ) {
+			length = strlen (document_end);
+			tag = string->str + string->len - 1;
+			i = 0;
+			valid = FALSE;
+			while (i < length - 1) {
+				gunichar c;
+
+				c = g_utf8_get_char (tag);
+				if (g_unichar_isspace (c)) {
+					tag = g_utf8_find_prev_char (string->str, tag);
+					continue;
+				}
+
+				c = g_unichar_tolower (c);
+
+				if (c == document_end[i]) {
+					tag = g_utf8_find_prev_char (string->str, tag);
+					i++;
+					valid = TRUE;
+					continue;
+				}
+
+				tag = g_utf8_find_prev_char (string->str, tag);
+				valid = FALSE;
+			}
+		}
+
+		if (valid)
+			g_string_truncate (string, tag - string->str);
+
+		camel_stream_write_string (stream, string->str, cancellable, NULL);
+
+		g_string_free (string, TRUE);
+	} else {
+		gchar *uri, *str;
+
+		uri = e_mail_part_build_uri (
+			context->folder, context->message_uid,
+			"part_id", G_TYPE_STRING, part->id,
+			"mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+			NULL);
+
+		str = g_strdup_printf (
+			"<div class=\"part-container-nostyle\">"
+			"<iframe width=\"100%%\" height=\"10\" "
+			" frameborder=\"0\" src=\"%s\" "
+			" id=\"%s.iframe\" "
+			" style=\"border: 1px solid #%06x; background-color: #%06x;\">"
+			"</iframe>"
+			"</div>",
+			uri,
+			part->id,
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_CONTENT)));
+
+		camel_stream_write_string (stream, str, cancellable, NULL);
+
+		g_free (str);
+		g_free (uri);
+	}
+
+	return TRUE;
+}
+
+static const gchar *
+emfe_text_html_get_display_name (EMailFormatterExtension *extension)
+{
+	return _("HTML");
+}
+
+static const gchar *
+emfe_text_html_get_description (EMailFormatterExtension *extension)
+{
+	return _("Format part as HTML");
+}
+
+static const gchar **
+emfe_text_html_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_text_html_class_init (EMailFormatterTextHTMLClass *klass)
+{
+	e_mail_formatter_text_html_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_text_html_format;
+	iface->get_display_name = emfe_text_html_get_display_name;
+	iface->get_description = emfe_text_html_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_text_html_mime_types;
+}
+
+static void
+e_mail_formatter_text_html_init (EMailFormatterTextHTML *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-text-plain.c b/em-format/e-mail-formatter-text-plain.c
new file mode 100644
index 0000000..631c46a
--- /dev/null
+++ b/em-format/e-mail-formatter-text-plain.c
@@ -0,0 +1,212 @@
+/*
+ * e-mail-formatter-text-plain.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+static const gchar *formatter_mime_types[] = { "text/plain", "text/*", NULL };
+
+typedef struct _EMailFormatterTextPlain {
+	GObject parent;
+} EMailFormatterTextPlain;
+
+typedef struct _EMailFormatterTextPlainClass {
+	GObjectClass parent_class;
+} EMailFormatterTextPlainClass;
+
+static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
+static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailFormatterTextPlain,
+	e_mail_formatter_text_plain,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_formatter_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_FORMATTER_EXTENSION,
+		e_mail_formatter_formatter_extension_interface_init));
+
+static gboolean
+emfe_text_plain_format (EMailFormatterExtension *extension,
+                        EMailFormatter *formatter,
+                        EMailFormatterContext *context,
+                        EMailPart *part,
+                        CamelStream *stream,
+                        GCancellable *cancellable)
+{
+	CamelDataWrapper *dw;
+	CamelStream *filtered_stream;
+	CamelMimeFilter *html_filter;
+	gchar *content;
+	const gchar *format;
+	guint32 filter_flags;
+	guint32 rgb;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return FALSE;
+
+	if ((context->mode == E_MAIL_FORMATTER_MODE_RAW) ||
+	    (context->mode == E_MAIL_FORMATTER_MODE_PRINTING)) {
+
+		if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
+			gchar *header;
+			header = e_mail_formatter_get_html_header (formatter);
+			camel_stream_write_string (stream, header, cancellable, NULL);
+			g_free (header);
+
+			/* No need for body margins within <iframe> */
+			camel_stream_write_string (stream,
+				"<style>body{ margin: 0; }</style>",
+				cancellable, NULL);
+		}
+
+		filter_flags = e_mail_formatter_get_text_format_flags (formatter);
+
+		dw = camel_medium_get_content (CAMEL_MEDIUM (part->part));
+		if (!dw)
+			return FALSE;
+
+		/* Check for RFC 2646 flowed text. */
+		if (camel_content_type_is(dw->mime_type, "text", "plain")
+		&& (format = camel_content_type_param(dw->mime_type, "format"))
+		&& !g_ascii_strcasecmp(format, "flowed"))
+			filter_flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;
+
+		rgb = e_color_to_value ((GdkColor *)
+			e_mail_formatter_get_color (
+				formatter, E_MAIL_FORMATTER_COLOR_CITATION));
+
+		filtered_stream = camel_stream_filter_new (stream);
+		html_filter = camel_mime_filter_tohtml_new (filter_flags, rgb);
+		camel_stream_filter_add (
+			CAMEL_STREAM_FILTER (filtered_stream), html_filter);
+		g_object_unref (html_filter);
+
+		content = g_strdup_printf (
+			"<div class=\"part-container\" style=\""
+			"border-color: #%06x;"
+			"background-color: #%06x; color: #%06x;\">"
+			"<div class=\"part-container-inner-margin pre\">\n",
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_CONTENT)),
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_TEXT)));
+
+		camel_stream_write_string (stream, content, cancellable, NULL);
+		e_mail_formatter_format_text (formatter, part, filtered_stream, cancellable);
+		camel_stream_flush (filtered_stream, cancellable, NULL);
+
+		g_object_unref (filtered_stream);
+		g_free (content);
+
+		camel_stream_write_string (stream, "</div></div>\n", cancellable, NULL);
+
+		if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
+			camel_stream_write_string (stream, "</body></html>",
+						   cancellable, NULL);
+		}
+
+		return TRUE;
+
+	} else {
+		gchar *uri, *str;
+
+		uri = e_mail_part_build_uri (
+			context->folder, context->message_uid,
+			"part_id", G_TYPE_STRING, part->id,
+			"mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+			NULL);
+
+		str = g_strdup_printf (
+			"<iframe width=\"100%%\" height=\"10\""
+			" id=\"%s.iframe\" "
+			" frameborder=\"0\" src=\"%s\"></iframe>",
+			part->id, uri);
+
+		camel_stream_write_string (stream, str, cancellable, NULL);
+
+		g_free (str);
+		g_free (uri);
+	}
+
+	return TRUE;
+}
+
+static const gchar *
+emfe_text_plain_get_display_name (EMailFormatterExtension *extension)
+{
+	return _("Plain Text");
+}
+
+static const gchar *
+emfe_text_plain_get_description (EMailFormatterExtension *extension)
+{
+	return _("Format part as plain text");
+}
+
+static const gchar **
+emfe_text_plain_mime_types (EMailExtension *extension)
+{
+	return formatter_mime_types;
+}
+
+static void
+e_mail_formatter_text_plain_class_init (EMailFormatterTextPlainClass *klass)
+{
+	e_mail_formatter_text_plain_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
+{
+	iface->format = emfe_text_plain_format;
+	iface->get_display_name = emfe_text_plain_get_display_name;
+	iface->get_description = emfe_text_plain_get_description;
+}
+
+static void
+e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = emfe_text_plain_mime_types;
+}
+
+static void
+e_mail_formatter_text_plain_init (EMailFormatterTextPlain *formatter)
+{
+
+}
diff --git a/em-format/e-mail-formatter-utils.c b/em-format/e-mail-formatter-utils.c
new file mode 100644
index 0000000..12ee042
--- /dev/null
+++ b/em-format/e-mail-formatter-utils.c
@@ -0,0 +1,434 @@
+/*
+ * e-mail-formatter-utils.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG
+#include <config.h>
+#endif
+
+#include "e-mail-formatter-utils.h"
+
+#include <camel/camel.h>
+
+#include <libemail-engine/e-mail-utils.h>
+#include <libemail-engine/mail-config.h>
+#include <e-util/e-util.h>
+#include <e-util/e-datetime-format.h>
+#include <libedataserver/libedataserver.h>
+
+#include <glib/gi18n.h>
+
+#include <string.h>
+
+static const gchar *addrspec_hdrs[] = {
+	"Sender", "From", "Reply-To", "To", "Cc", "Bcc",
+	"Resent-Sender", "Resent-From", "Resent-Reply-To",
+	"Resent-To", "Resent-Cc", "Resent-Bcc", NULL
+};
+
+void
+e_mail_formatter_format_text_header (EMailFormatter *formatter,
+                                     GString *buffer,
+                                     const gchar *label,
+                                     const gchar *value,
+                                     guint32 flags)
+{
+	const gchar *fmt, *html;
+	gchar *mhtml = NULL;
+	gboolean is_rtl;
+
+	if (value == NULL)
+		return;
+
+	while (*value == ' ')
+		value++;
+
+	if (!(flags & E_MAIL_FORMATTER_HEADER_FLAG_HTML))
+		html = mhtml = camel_text_to_html (value,
+			e_mail_formatter_get_text_format_flags (formatter), 0);
+	else
+		html = value;
+
+	is_rtl = gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL;
+
+	if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS) {
+		if (flags & E_MAIL_FORMATTER_HEADER_FLAG_BOLD) {
+			fmt = "<tr class=\"header-item\" style=\"display: %s\"><td><b>%s:</b> %s</td></tr>";
+		} else {
+			fmt = "<tr class=\"header-item\" style=\"display: %s\"><td>%s: %s</td></tr>";
+		}
+	} else if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NODEC) {
+		if (is_rtl)
+			fmt = "<tr class=\"header-item rtl\" style=\"display: %s\"><td align=\"right\" valign=\"top\" width=\"100%%\">%2$s</td><th valign=top align=\"left\" nowrap>%1$s<b>&nbsp;</b></th></tr>";
+		else
+			fmt = "<tr class=\"header-item\" style=\"display: %s\"><th align=\"right\" valign=\"top\" nowrap>%s<b>&nbsp;</b></th><td valign=top>%s</td></tr>";
+	} else {
+		if (flags & E_MAIL_FORMATTER_HEADER_FLAG_BOLD) {
+			if (is_rtl)
+				fmt = "<tr class=\"header-item rtl\" style=\"display: %s\"><td align=\"right\" valign=\"top\" width=\"100%%\">%2$s</td><th align=\"left\" nowrap>%1$s:<b>&nbsp;</b></th></tr>";
+			else
+				fmt = "<tr class=\"header-item\" style=\"display: %s\"><th align=\"right\" valign=\"top\" nowrap>%s:<b>&nbsp;</b></th><td>%s</td></tr>";
+		} else {
+			if (is_rtl)
+				fmt = "<tr class=\"header-item rtl\" style=\"display: %s\"><td align=\"right\" valign=\"top\" width=\"100%\">%2$s</td><td align=\"left\" nowrap>%1$s:<b>&nbsp;</b></td></tr>";
+			else
+				fmt = "<tr class=\"header-item\" style=\"display: %s\"><td align=\"right\" valign=\"top\" nowrap>%s:<b>&nbsp;</b></td><td>%s</td></tr>";
+		}
+	}
+
+	g_string_append_printf (buffer, fmt,
+		(flags & E_MAIL_FORMATTER_HEADER_FLAG_HIDDEN ? "none" : "table-row"), label, html);
+
+	g_free (mhtml);
+}
+
+gchar *
+e_mail_formatter_format_address (EMailFormatter *formatter,
+                                 GString *out,
+                                 struct _camel_header_address *a,
+                                 gchar *field,
+                                 gboolean no_links,
+                                 gboolean elipsize)
+{
+	guint32 flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
+	gchar *name, *mailto, *addr;
+	gint i = 0;
+	gchar *str = NULL;
+	gint limit = mail_config_get_address_count ();
+
+	while (a) {
+		if (a->name)
+			name = camel_text_to_html (a->name, flags, 0);
+		else
+			name = NULL;
+
+		switch (a->type) {
+		case CAMEL_HEADER_ADDRESS_NAME:
+			if (name && *name) {
+				gchar *real, *mailaddr;
+
+				if (strchr (a->name, ',') || strchr (a->name, ';'))
+					g_string_append_printf (out, "&quot;%s&quot;", name);
+				else
+					g_string_append (out, name);
+
+				g_string_append (out, " &lt;");
+
+				/* rfc2368 for mailto syntax and url encoding extras */
+				if ((real = camel_header_encode_phrase ((guchar *) a->name))) {
+					mailaddr = g_strdup_printf("%s <%s>", real, a->v.addr);
+					g_free (real);
+					mailto = camel_url_encode (mailaddr, "?=&()");
+					g_free (mailaddr);
+				} else {
+					mailto = camel_url_encode (a->v.addr, "?=&()");
+				}
+			} else {
+				mailto = camel_url_encode (a->v.addr, "?=&()");
+			}
+			addr = camel_text_to_html (a->v.addr, flags, 0);
+			if (no_links)
+				g_string_append_printf (out, "%s", addr);
+			else
+				g_string_append_printf (out, "<a href=\"mailto:%s\";>%s</a>", mailto, addr);
+			g_free (mailto);
+			g_free (addr);
+
+			if (name && *name)
+				g_string_append (out, "&gt;");
+			break;
+		case CAMEL_HEADER_ADDRESS_GROUP:
+			g_string_append_printf (out, "%s: ", name);
+			e_mail_formatter_format_address (
+				formatter, out, a->v.members, field,
+				no_links, elipsize);
+			g_string_append_printf (out, ";");
+			break;
+		default:
+			g_warning ("Invalid address type");
+			break;
+		}
+
+		g_free (name);
+
+		i++;
+		a = a->next;
+		if (a)
+			g_string_append (out, ", ");
+
+		if (!elipsize)
+			continue;
+
+		/* Let us add a '...' if we have more addresses */
+		if (limit > 0 && (i == limit - 1)) {
+			const gchar *id = NULL;
+
+			if (strcmp (field, _("To")) == 0) {
+				id = "to";
+			} else if (strcmp (field, _("Cc")) == 0) {
+				id = "cc";
+			} else if (strcmp (field, _("Bcc")) == 0) {
+				id = "bcc";
+			}
+
+			if (id) {
+				g_string_append_printf (out,
+					"<span id=\"__evo-moreaddr-%s\" "
+					      "style=\"display: none;\">", id);
+				str = g_strdup_printf (
+					"<img src=\"evo-file://%s/plus.png\" "
+					     "id=\"__evo-moreaddr-img-%s\" class=\"navigable\">",
+					EVOLUTION_IMAGESDIR, id);
+			}
+		}
+	}
+
+	if (elipsize && str) {
+		const gchar *id = NULL;
+
+		if (strcmp (field, _("To")) == 0) {
+			id = "to";
+		} else if (strcmp (field, _("Cc")) == 0) {
+			id = "cc";
+		} else if (strcmp (field, _("Bcc")) == 0) {
+			id = "bcc";
+		}
+
+		if (id) {
+			g_string_append_printf (out,
+				"</span>"
+				"<span class=\"navigable\" "
+					"id=\"__evo-moreaddr-ellipsis-%s\" "
+					"style=\"display: inline;\">...</span>",
+				id);
+		}
+	}
+
+	return str;
+}
+
+void
+e_mail_formatter_canon_header_name (gchar *name)
+{
+	gchar *inptr = name;
+
+	/* canonicalise the header name... first letter is
+	 * capitalised and any letter following a '-' also gets
+	 * capitalised */
+
+	if (*inptr >= 'a' && *inptr <= 'z')
+		*inptr -= 0x20;
+
+	inptr++;
+
+	while (*inptr) {
+		if (inptr[-1] == '-' && *inptr >= 'a' && *inptr <= 'z')
+			*inptr -= 0x20;
+		else if (*inptr >= 'A' && *inptr <= 'Z')
+			*inptr += 0x20;
+
+		inptr++;
+	}
+}
+
+void
+e_mail_formatter_format_header (EMailFormatter *formatter,
+                                GString *buffer,
+                                CamelMedium *part,
+                                struct _camel_header_raw *header,
+                                guint32 flags,
+                                const gchar *charset)
+{
+	gchar *name, *buf, *value = NULL;
+	const gchar *label, *txt;
+	gboolean addrspec = FALSE;
+	gchar *str_field = NULL;
+	gint i;
+
+	name = g_alloca (strlen (header->name) + 1);
+	strcpy (name, header->name);
+	e_mail_formatter_canon_header_name (name);
+
+	for (i = 0; addrspec_hdrs[i]; i++) {
+		if (!strcmp (name, addrspec_hdrs[i])) {
+			addrspec = TRUE;
+			break;
+		}
+	}
+
+	label = _(name);
+
+	if (addrspec) {
+		struct _camel_header_address *addrs;
+		GString *html;
+		gchar *img;
+		const gchar *charset = e_mail_formatter_get_charset (formatter) ?
+						e_mail_formatter_get_charset (formatter) :
+						e_mail_formatter_get_default_charset (formatter);
+
+		buf = camel_header_unfold (header->value);
+		if (!(addrs = camel_header_address_decode (buf, charset))) {
+			g_free (buf);
+			return;
+		}
+
+		g_free (buf);
+
+		html = g_string_new("");
+		img = e_mail_formatter_format_address (formatter, html, addrs, (gchar *) label,
+			(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS),
+			!(flags & E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE));
+
+		if (img) {
+			str_field = g_strdup_printf ("%s%s:", img, label);
+			label = str_field;
+			flags |= E_MAIL_FORMATTER_HEADER_FLAG_NODEC;
+			g_free (img);
+		}
+
+		camel_header_address_list_clear (&addrs);
+		txt = value = html->str;
+		g_string_free (html, FALSE);
+
+		flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML | E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+	} else if (!strcmp (name, "Subject")) {
+		buf = camel_header_unfold (header->value);
+		txt = value = camel_header_decode_string (buf, charset);
+		g_free (buf);
+
+		flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+	} else if (!strcmp(name, "X-evolution-mailer")) {
+		/* pseudo-header */
+		label = _("Mailer");
+		txt = value = camel_header_format_ctext (header->value, charset);
+		flags |= E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+	} else if (!strcmp (name, "Date") || !strcmp (name, "Resent-Date")) {
+		gint msg_offset, local_tz;
+		time_t msg_date;
+		struct tm local;
+		gchar *html;
+		gboolean hide_real_date;
+
+		hide_real_date = !e_mail_formatter_get_show_real_date (formatter);
+
+		txt = header->value;
+		while (*txt == ' ' || *txt == '\t')
+			txt++;
+
+		html = camel_text_to_html (txt,
+			e_mail_formatter_get_text_format_flags (formatter), 0);
+
+		msg_date = camel_header_decode_date (txt, &msg_offset);
+		e_localtime_with_offset (msg_date, &local, &local_tz);
+
+		/* Convert message offset to minutes (e.g. -0400 --> -240) */
+		msg_offset = ((msg_offset / 100) * 60) + (msg_offset % 100);
+		/* Turn into offset from localtime, not UTC */
+		msg_offset -= local_tz / 60;
+
+		/* value will be freed at the end */
+		if (!hide_real_date && !msg_offset) {
+			/* No timezone difference; just show the real Date: header */
+			txt = value = html;
+		} else {
+			gchar *date_str;
+
+			date_str = e_datetime_format_format ("mail", "header",
+							     DTFormatKindDateTime, msg_date);
+
+			if (hide_real_date) {
+				/* Show only the local-formatted date, losing all timezone
+				 * information like Outlook does. Should we attempt to show
+				 * it somehow? */
+				txt = value = date_str;
+			} else {
+				txt = value = g_strdup_printf ("%s (<I>%s</I>)", html, date_str);
+				g_free (date_str);
+			}
+			g_free (html);
+		}
+		flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML |
+			 E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+	} else if (!strcmp(name, "Newsgroups")) {
+		struct _camel_header_newsgroup *ng, *scan;
+		GString *html;
+
+		buf = camel_header_unfold (header->value);
+
+		if (!(ng = camel_header_newsgroups_decode (buf))) {
+			g_free (buf);
+			return;
+		}
+
+		g_free (buf);
+
+		html = g_string_new("");
+		scan = ng;
+		while (scan) {
+			if (flags & E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS)
+				g_string_append_printf (html, "%s", scan->newsgroup);
+			else
+				g_string_append_printf(html, "<a href=\"news:%s\";>%s</a>",
+					scan->newsgroup, scan->newsgroup);
+			scan = scan->next;
+			if (scan)
+				g_string_append_printf(html, ", ");
+		}
+
+		camel_header_newsgroups_free (ng);
+
+		txt = html->str;
+		g_string_free (html, FALSE);
+		flags |= E_MAIL_FORMATTER_HEADER_FLAG_HTML |
+			 E_MAIL_FORMATTER_HEADER_FLAG_BOLD;
+	} else if (!strcmp (name, "Received") || !strncmp (name, "X-", 2)) {
+		/* don't unfold Received nor extension headers */
+		txt = value = camel_header_decode_string (header->value, charset);
+	} else {
+		/* don't unfold Received nor extension headers */
+		buf = camel_header_unfold (header->value);
+		txt = value = camel_header_decode_string (buf, charset);
+		g_free (buf);
+	}
+
+	e_mail_formatter_format_text_header (formatter, buffer, label, txt, flags);
+
+	g_free (value);
+	g_free (str_field);
+}
+
+GSList *
+e_mail_formatter_find_rfc822_end_iter (GSList *iter)
+{
+	EMailPart *part;
+	gchar *end;
+
+	part = iter->data;
+	end = g_strconcat (part->id, ".end", NULL);
+	for (; iter != NULL; iter = g_slist_next (iter)) {
+		part = iter->data;
+		if (!part)
+			continue;
+
+		if (g_strcmp0 (part->id, end) == 0) {
+			g_free (end);
+			return iter;
+		}
+	}
+	g_free (end);
+	return iter;
+}
diff --git a/em-format/e-mail-formatter-utils.h b/em-format/e-mail-formatter-utils.h
new file mode 100644
index 0000000..59d8e43
--- /dev/null
+++ b/em-format/e-mail-formatter-utils.h
@@ -0,0 +1,56 @@
+/*
+ * e-mail-formatter-utils.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_UTILS_H_
+#define E_MAIL_FORMATTER_UTILS_H_
+
+#include <camel/camel.h>
+#include <em-format/e-mail-formatter.h>
+
+G_BEGIN_DECLS
+
+void		e_mail_formatter_format_header (EMailFormatter *formatter,
+						GString *buffer,
+						CamelMedium *part,
+						struct _camel_header_raw *header,
+						guint32 flags,
+						const gchar *charset);
+
+void		e_mail_formatter_format_text_header
+						(EMailFormatter *formatter,
+						 GString *buffer,
+						 const gchar *label,
+						 const gchar *value,
+						 guint32 flags);
+
+gchar *		e_mail_formatter_format_address (EMailFormatter *formatter,
+						 GString *out,
+						 struct _camel_header_address *a,
+						 gchar *field,
+						 gboolean no_links,
+						 gboolean elipsize);
+
+void		e_mail_formatter_canon_header_name
+						(gchar *name);
+
+GSList *		e_mail_formatter_find_rfc822_end_iter
+						(GSList *rfc822_start_iter);
+
+G_END_DECLS
+
+#endif /* E_MAIL_FORMATTER_UTILS_H_ */
diff --git a/em-format/e-mail-formatter.c b/em-format/e-mail-formatter.c
new file mode 100644
index 0000000..a08504a
--- /dev/null
+++ b/em-format/e-mail-formatter.c
@@ -0,0 +1,1510 @@
+/*
+ * e-mail-formatter.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-formatter.h"
+
+#include <camel/camel.h>
+
+#include "e-mail-formatter-extension.h"
+#include "e-mail-formatter-utils.h"
+#include "e-mail-part.h"
+
+#include "e-mail-format-extensions.h"
+
+#include <e-util/e-util.h>
+#include <libebackend/libebackend.h>
+#include <gdk/gdk.h>
+#include <glib/gi18n.h>
+
+#define d(x)
+
+struct _EMailFormatterPrivate {
+	EMailImageLoadingPolicy image_loading_policy;
+
+	guint only_local_photos	: 1;
+	guint show_sender_photo	: 1;
+	guint show_real_date	: 1;
+        guint animate_images    : 1;
+
+	gchar *charset;
+	gchar *default_charset;
+
+	GQueue *header_list;
+};
+
+#define E_MAIL_FORMATTER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_MAIL_FORMATTER, EMailFormatterPrivate))\
+
+static gpointer e_mail_formatter_parent_class = 0;
+
+enum {
+	PROP_0,
+	PROP_BODY_COLOR,
+	PROP_CITATION_COLOR,
+	PROP_CONTENT_COLOR,
+	PROP_FRAME_COLOR,
+	PROP_HEADER_COLOR,
+	PROP_TEXT_COLOR,
+	PROP_IMAGE_LOADING_POLICY,
+	PROP_FORCE_IMAGE_LOADING,
+	PROP_MARK_CITATIONS,
+	PROP_ONLY_LOCAL_PHOTOS,
+	PROP_SHOW_SENDER_PHOTO,
+	PROP_SHOW_REAL_DATE,
+        PROP_ANIMATE_IMAGES,
+	PROP_CHARSET,
+	PROP_DEFAULT_CHARSET
+};
+
+static void
+mail_formatter_run (EMailFormatter *formatter,
+                    EMailFormatterContext *context,
+                    CamelStream *stream,
+                    GCancellable *cancellable)
+{
+	GSList *iter;
+	gchar *hdr;
+
+	hdr = e_mail_formatter_get_html_header (formatter);
+	camel_stream_write_string (stream, hdr, cancellable, NULL);
+	g_free (hdr);
+
+	for (iter = context->parts; iter; iter = iter->next) {
+
+		EMailPart *part;
+		gboolean ok;
+
+		if (g_cancellable_is_cancelled (cancellable))
+			break;
+
+		part = iter->data;
+		if (!part)
+			continue;
+
+		if (part->is_hidden && !part->is_error) {
+			if (g_str_has_suffix (part->id, ".rfc822")) {
+				iter = e_mail_formatter_find_rfc822_end_iter (iter);
+			}
+
+			if (!iter)
+				break;
+
+			continue;
+		}
+
+		/* Force formatting as source if needed */
+		if (context->mode != E_MAIL_FORMATTER_MODE_SOURCE) {
+
+			if (!part->mime_type)
+				continue;
+
+			ok = e_mail_formatter_format_as (
+				formatter, context, part, stream,
+				part->mime_type, cancellable);
+
+			/* If the written part was message/rfc822 then
+			 * jump to the end of the message, because content
+			 * of the whole message has been formatted by
+			 * message_rfc822 formatter */
+			if (ok && g_str_has_suffix (part->id, ".rfc822")) {
+				iter = e_mail_formatter_find_rfc822_end_iter (iter);
+
+				if (!iter)
+					break;
+
+				continue;
+			}
+
+		} else {
+			ok = FALSE;
+		}
+
+		if (!ok) {
+			/* We don't want to source these */
+			if (g_str_has_suffix (part->id, ".headers") ||
+			    g_str_has_suffix (part->id, "attachment-bar"))
+				continue;
+
+			e_mail_formatter_format_as (
+				formatter, context, part, stream,
+				"application/vnd.evolution.source", cancellable);
+
+			/* .message is the entire message. There's nothing more
+			 * to be written. */
+			if (g_strcmp0 (part->id, ".message") == 0)
+				break;
+
+			/* If we just wrote source of a rfc822 message, then jump
+			 * behind the message (otherwise source of all parts
+			 * would be rendered twice) */
+			if (g_str_has_suffix (part->id, ".rfc822")) {
+
+				do {
+					part = iter->data;
+					if (part && g_str_has_suffix (part->id, ".rfc822.end"))
+						break;
+
+					iter = iter->next;
+				} while (iter);
+			}
+		}
+	}
+
+	camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
+}
+
+static EMailFormatterContext *
+mail_formatter_create_context (EMailFormatter *formatter)
+{
+	EMailFormatterClass *formatter_class;
+
+	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+
+	if (formatter_class->create_context) {
+		if (!formatter_class->free_context) {
+			g_warning ("%s implements create_context() but "
+				   "does not implement free_context()!",
+				   G_OBJECT_TYPE_NAME (formatter));
+		}
+
+		return formatter_class->create_context (formatter);
+	}
+
+	return g_new0 (EMailFormatterContext, 1);
+}
+
+static void
+mail_formatter_free_context (EMailFormatter *formatter,
+                             EMailFormatterContext *context)
+{
+	EMailFormatterClass *formatter_class;
+
+	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+
+	if (formatter_class->free_context) {
+		formatter_class->free_context (formatter, context);
+	} else {
+		g_free (context);
+	}
+}
+
+static void
+mail_formatter_set_style (EMailFormatter *formatter,
+                          GtkStyle *style,
+                          GtkStateType state)
+{
+	GdkColor *color;
+	EMailFormatterColorType type;
+
+	g_object_freeze_notify (G_OBJECT (formatter));
+
+	color = &style->bg[state];
+	type = E_MAIL_FORMATTER_COLOR_BODY;
+	e_mail_formatter_set_color (formatter, type, color);
+
+	color = &style->base[GTK_STATE_NORMAL];
+	type = E_MAIL_FORMATTER_COLOR_CONTENT;
+	e_mail_formatter_set_color  (formatter, type, color);
+
+	color = &style->dark[state];
+	type = E_MAIL_FORMATTER_COLOR_FRAME;
+	e_mail_formatter_set_color  (formatter, type, color);
+
+	color = &style->fg[state];
+	type = E_MAIL_FORMATTER_COLOR_HEADER;
+	e_mail_formatter_set_color  (formatter, type, color);
+
+	color = &style->text[state];
+	type = E_MAIL_FORMATTER_COLOR_TEXT;
+	e_mail_formatter_set_color  (formatter, type, color);
+
+	g_object_thaw_notify (G_OBJECT (formatter));
+}
+
+static void
+e_mail_formatter_set_property (GObject *object,
+                               guint property_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_BODY_COLOR:
+			e_mail_formatter_set_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_BODY,
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_CITATION_COLOR:
+			e_mail_formatter_set_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_CITATION,
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_CONTENT_COLOR:
+			e_mail_formatter_set_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_CONTENT,
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_FRAME_COLOR:
+			e_mail_formatter_set_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_FRAME,
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_HEADER_COLOR:
+			e_mail_formatter_set_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_HEADER,
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_IMAGE_LOADING_POLICY:
+			e_mail_formatter_set_image_loading_policy (
+				E_MAIL_FORMATTER (object),
+				g_value_get_int (value));
+			return;
+
+		case PROP_MARK_CITATIONS:
+			e_mail_formatter_set_mark_citations (
+				E_MAIL_FORMATTER (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_ONLY_LOCAL_PHOTOS:
+			e_mail_formatter_set_only_local_photos (
+				E_MAIL_FORMATTER (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_SHOW_SENDER_PHOTO:
+			e_mail_formatter_set_show_sender_photo (
+				E_MAIL_FORMATTER (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_SHOW_REAL_DATE:
+			e_mail_formatter_set_show_real_date (
+				E_MAIL_FORMATTER (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_TEXT_COLOR:
+			e_mail_formatter_set_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_TEXT,
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_ANIMATE_IMAGES:
+			e_mail_formatter_set_animate_images (
+				E_MAIL_FORMATTER (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_CHARSET:
+			e_mail_formatter_set_charset (
+				E_MAIL_FORMATTER (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_DEFAULT_CHARSET:
+			e_mail_formatter_set_default_charset (
+				E_MAIL_FORMATTER (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_formatter_get_property (GObject *object,
+                             guint property_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_BODY_COLOR:
+			g_value_set_boxed (value,
+			e_mail_formatter_get_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_BODY));
+			return;
+
+		case PROP_CITATION_COLOR:
+			g_value_set_boxed (value,
+			e_mail_formatter_get_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_CITATION));
+			return;
+
+		case PROP_CONTENT_COLOR:
+			g_value_set_boxed (value,
+			e_mail_formatter_get_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_CONTENT));
+			return;
+
+		case PROP_FRAME_COLOR:
+			g_value_set_boxed (value,
+			e_mail_formatter_get_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_FRAME));
+			return;
+
+		case PROP_HEADER_COLOR:
+			g_value_set_boxed (value,
+			e_mail_formatter_get_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_HEADER));
+			return;
+
+		case PROP_IMAGE_LOADING_POLICY:
+			g_value_set_int (
+				value,
+				e_mail_formatter_get_image_loading_policy (
+				E_MAIL_FORMATTER (object)));
+			return;
+
+		case PROP_MARK_CITATIONS:
+			g_value_set_boolean (
+				value, e_mail_formatter_get_mark_citations (
+				E_MAIL_FORMATTER (object)));
+			return;
+
+		case PROP_ONLY_LOCAL_PHOTOS:
+			g_value_set_boolean (
+				value, e_mail_formatter_get_only_local_photos (
+				E_MAIL_FORMATTER (object)));
+			return;
+
+		case PROP_SHOW_SENDER_PHOTO:
+			g_value_set_boolean (
+				value, e_mail_formatter_get_show_sender_photo (
+				E_MAIL_FORMATTER (object)));
+			return;
+
+		case PROP_SHOW_REAL_DATE:
+			g_value_set_boolean (
+				value, e_mail_formatter_get_show_real_date (
+				E_MAIL_FORMATTER (object)));
+			return;
+
+		case PROP_TEXT_COLOR:
+			g_value_set_boxed (value,
+			e_mail_formatter_get_color (
+				E_MAIL_FORMATTER (object),
+				E_MAIL_FORMATTER_COLOR_TEXT));
+			return;
+
+		case PROP_ANIMATE_IMAGES:
+			g_value_set_boolean (
+				value, e_mail_formatter_get_animate_images (
+				E_MAIL_FORMATTER (object)));
+			return;
+
+		case PROP_CHARSET:
+			g_value_set_string (
+				value, e_mail_formatter_get_charset (
+				E_MAIL_FORMATTER (object)));
+			return;
+
+		case PROP_DEFAULT_CHARSET:
+			g_value_set_string (
+				value, e_mail_formatter_get_default_charset (
+				E_MAIL_FORMATTER (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_formatter_init (EMailFormatter *formatter)
+{
+	formatter->priv = E_MAIL_FORMATTER_GET_PRIVATE (formatter);
+
+	formatter->priv->header_list = g_queue_new ();
+	e_mail_formatter_set_default_headers (formatter);
+}
+
+static void
+e_mail_formatter_finalize (GObject *object)
+{
+	EMailFormatterPrivate *priv;
+
+	priv = E_MAIL_FORMATTER (object)->priv;
+
+	if (priv->charset) {
+		g_free (priv->charset);
+		priv->charset = NULL;
+	}
+
+	if (priv->default_charset) {
+		g_free (priv->default_charset);
+		priv->default_charset = NULL;
+	}
+
+	if (priv->header_list) {
+		e_mail_formatter_clear_headers (E_MAIL_FORMATTER (object));
+		g_queue_free (priv->header_list);
+		priv->header_list = NULL;
+	}
+
+	/* Chain up to parent's finalize() */
+	G_OBJECT_CLASS (e_mail_formatter_parent_class)->finalize (object);
+}
+
+static void
+e_mail_formatter_base_init (EMailFormatterClass *klass)
+{
+	klass->extension_registry = g_object_new (
+		E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY, NULL);
+
+	e_mail_formatter_internal_extensions_load (
+			E_MAIL_EXTENSION_REGISTRY (klass->extension_registry));
+
+	e_extensible_load_extensions (
+		E_EXTENSIBLE (klass->extension_registry));
+
+	klass->text_html_flags =
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
+		CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+}
+
+static void
+e_mail_formatter_base_finalize (EMailFormatterClass *klass)
+{
+	g_object_unref (klass->extension_registry);
+}
+
+static void
+e_mail_formatter_constructed (GObject *object)
+{
+	G_OBJECT_CLASS (e_mail_formatter_parent_class)->constructed (object);
+
+	e_extensible_load_extensions (E_EXTENSIBLE (object));
+}
+
+static void
+e_mail_formatter_class_init (EMailFormatterClass *klass)
+{
+	GObjectClass *object_class;
+	GdkColor *color;
+
+	e_mail_formatter_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (EMailFormatterPrivate));
+
+	klass->run = mail_formatter_run;
+
+	/* EMailFormatter calls these directly */
+	klass->create_context = NULL;
+	klass->free_context = NULL;
+	klass->set_style = mail_formatter_set_style;
+
+	color = &klass->colors[E_MAIL_FORMATTER_COLOR_BODY];
+	gdk_color_parse ("#eeeeee", color);
+
+	color = &klass->colors[E_MAIL_FORMATTER_COLOR_CONTENT];
+	gdk_color_parse ("#ffffff", color);
+
+	color = &klass->colors[E_MAIL_FORMATTER_COLOR_FRAME];
+	gdk_color_parse ("#3f3f3f", color);
+
+	color = &klass->colors[E_MAIL_FORMATTER_COLOR_HEADER];
+	gdk_color_parse ("#eeeeee", color);
+
+	color = &klass->colors[E_MAIL_FORMATTER_COLOR_TEXT];
+	gdk_color_parse ("#000000", color);
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->constructed = e_mail_formatter_constructed;
+	object_class->get_property = e_mail_formatter_get_property;
+	object_class->set_property = e_mail_formatter_set_property;
+	object_class->finalize = e_mail_formatter_finalize;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_BODY_COLOR,
+		g_param_spec_boxed (
+			"body-color",
+			"Body Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CITATION_COLOR,
+		g_param_spec_boxed (
+			"citation-color",
+			"Citation Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CONTENT_COLOR,
+		g_param_spec_boxed (
+			"content-color",
+			"Content Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FRAME_COLOR,
+		g_param_spec_boxed (
+			"frame-color",
+			"Frame Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_HEADER_COLOR,
+		g_param_spec_boxed (
+			"header-color",
+			"Header Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
+
+	/* FIXME Make this a proper enum property. */
+	g_object_class_install_property (
+		object_class,
+		PROP_IMAGE_LOADING_POLICY,
+		g_param_spec_int (
+			"image-loading-policy",
+			"Image Loading Policy",
+			NULL,
+			E_MAIL_IMAGE_LOADING_POLICY_NEVER,
+			E_MAIL_IMAGE_LOADING_POLICY_ALWAYS,
+			E_MAIL_IMAGE_LOADING_POLICY_NEVER,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MARK_CITATIONS,
+		g_param_spec_boolean (
+			"mark-citations",
+			"Mark Citations",
+			NULL,
+			TRUE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ONLY_LOCAL_PHOTOS,
+		g_param_spec_boolean (
+			"only-local-photos",
+			"Only Local Photos",
+			NULL,
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SHOW_SENDER_PHOTO,
+		g_param_spec_boolean (
+			"show-sender-photo",
+			"Show Sender Photo",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SHOW_REAL_DATE,
+		g_param_spec_boolean (
+			"show-real-date",
+			"Show real Date header value",
+			NULL,
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_TEXT_COLOR,
+		g_param_spec_boxed (
+			"text-color",
+			"Text Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ANIMATE_IMAGES,
+		g_param_spec_boolean (
+			"animate-images",
+			"Animate images",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CHARSET,
+		g_param_spec_string (
+			"charset",
+			NULL,
+			NULL,
+			NULL,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DEFAULT_CHARSET,
+		g_param_spec_string (
+			"default-charset",
+			NULL,
+			NULL,
+			NULL,
+			G_PARAM_READWRITE));
+}
+
+static void
+e_mail_formatter_extensible_interface_init (EExtensibleInterface *interface)
+{
+
+}
+
+EMailFormatter *
+e_mail_formatter_new (void)
+{
+	return g_object_new (E_TYPE_MAIL_FORMATTER, NULL);
+}
+
+GType
+e_mail_formatter_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		const GTypeInfo type_info = {
+			sizeof (EMailFormatterClass),
+			(GBaseInitFunc) e_mail_formatter_base_init,
+			(GBaseFinalizeFunc) e_mail_formatter_base_finalize,
+			(GClassInitFunc) e_mail_formatter_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,	/* class_data */
+			sizeof (EMailFormatter),
+			0,	/* n_preallocs */
+			(GInstanceInitFunc) e_mail_formatter_init,
+			NULL	/* value_table */
+		};
+
+		const GInterfaceInfo e_extensible_interface_info = {
+			(GInterfaceInitFunc) e_mail_formatter_extensible_interface_init
+		};
+
+		type = g_type_register_static (G_TYPE_OBJECT,
+				"EMailFormatter", &type_info, 0);
+
+		g_type_add_interface_static (type,
+			E_TYPE_EXTENSIBLE, &e_extensible_interface_info);
+	}
+
+	return type;
+}
+
+void
+e_mail_formatter_format_sync (EMailFormatter *formatter,
+                              EMailPartList *parts,
+                              CamelStream *stream,
+                              guint32 flags,
+                              EMailFormatterMode mode,
+                              GCancellable *cancellable)
+{
+	EMailFormatterContext *context;
+	EMailFormatterClass *formatter_class;
+
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+	g_return_if_fail (CAMEL_IS_STREAM (stream));
+
+	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+	g_return_if_fail (formatter_class->run != NULL);
+
+	context = mail_formatter_create_context (formatter);
+	context->message = parts->message;
+	context->folder = parts->folder;
+	context->message_uid = parts->message_uid;
+	context->parts = parts->list;
+	context->flags = flags;
+	context->mode = mode;
+
+	formatter_class->run (
+		formatter, context, stream, cancellable);
+
+	mail_formatter_free_context (formatter, context);
+}
+
+static void
+mail_format_async_prepare (GSimpleAsyncResult *result,
+                           GObject *object,
+                           GCancellable *cancellable)
+{
+	EMailFormatterContext *context;
+	EMailFormatterClass *formatter_class;
+	CamelStream *stream;
+
+	context = g_object_get_data (G_OBJECT (result), "context");
+	stream = g_object_get_data (G_OBJECT (result), "stream");
+
+	formatter_class = E_MAIL_FORMATTER_GET_CLASS (object);
+	formatter_class->run (
+		E_MAIL_FORMATTER (object), context, stream, cancellable);
+}
+
+void
+e_mail_formatter_format (EMailFormatter *formatter,
+                         EMailPartList *parts,
+                         CamelStream *stream,
+                         guint32 flags,
+                         EMailFormatterMode mode,
+                         GAsyncReadyCallback callback,
+                         GCancellable *cancellable,
+                         gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	EMailFormatterContext *context;
+	EMailFormatterClass *formatter_class;
+
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+	g_return_if_fail (CAMEL_IS_STREAM (stream));
+
+	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+	g_return_if_fail (formatter_class->run != NULL);
+
+	simple = g_simple_async_result_new (
+			G_OBJECT (formatter), callback,
+			user_data, e_mail_formatter_format);
+
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	if (!parts && callback) {
+		callback (G_OBJECT (formatter), G_ASYNC_RESULT (simple), user_data);
+		g_object_unref (simple);
+		return;
+	}
+
+	context = mail_formatter_create_context (formatter);
+	context->message = g_object_ref (parts->message);
+	context->folder = g_object_ref (parts->folder);
+	context->message_uid = g_strdup (parts->message_uid);
+	context->parts = g_slist_copy (parts->list);
+	g_slist_foreach (context->parts, (GFunc) e_mail_part_ref, NULL);
+	context->flags = flags;
+	context->mode = mode;
+
+	g_object_set_data (G_OBJECT (simple), "context", context);
+	g_object_set_data (G_OBJECT (simple), "stream", stream);
+
+	g_simple_async_result_run_in_thread (
+		simple, mail_format_async_prepare,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
+}
+
+CamelStream *
+e_mail_formatter_format_finished (EMailFormatter *formatter,
+                                  GAsyncResult *result,
+                                  GError *error)
+{
+	EMailFormatterContext *context;
+
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	context = g_object_get_data (G_OBJECT (result), "context");	
+
+	g_free (context->message_uid);
+	g_object_unref (context->message);
+	g_object_unref (context->folder);
+	g_slist_foreach (context->parts, (GFunc) e_mail_part_unref, NULL);
+	g_slist_free (context->parts);
+	mail_formatter_free_context (formatter, context);
+
+	return g_object_get_data (G_OBJECT (result), "stream");
+}
+
+/**
+ * e_mail_formatter_format_as:
+ * @formatter: an #EMailFormatter
+ * @context: an #EMailFormatterContext
+ * @part: an #EMailPart
+ * @stream: a #CamelStream
+ * @as_mime_type: (allow-none) mime-type to use for formatting, or %NULL
+ * @cancellable: (allow-none) an optional #GCancellable
+ *
+ * Formats given @part using a @formatter extension for given mime type. When
+ * the mime type is %NULL, the function will try to lookup the best formatter
+ * for given @part by it's default mime type.
+ *
+ * Return Value: %TRUE on success, %FALSE when no suitable formatter is found or
+ * when it fails to format the part. 
+ */
+gboolean
+e_mail_formatter_format_as (EMailFormatter *formatter,
+                            EMailFormatterContext *context,
+                            EMailPart *part,
+                            CamelStream *stream,
+                            const gchar *as_mime_type,
+                            GCancellable *cancellable)
+{
+	EMailExtensionRegistry *reg;
+	GQueue *formatters;
+	GList *iter;
+	gboolean ok;
+	d (
+		gint _call_i;
+		static gint _call = 0;
+		G_LOCK_DEFINE_STATIC (_call);
+		G_LOCK (_call);
+		_call++;
+		_call_i = _call;
+		G_UNLOCK (_call)
+	);
+
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+	g_return_val_if_fail (part, FALSE);
+	g_return_val_if_fail (CAMEL_IS_STREAM (stream), FALSE);
+
+	if (!as_mime_type || !*as_mime_type)
+		as_mime_type = part->mime_type;
+
+	if (!as_mime_type || !*as_mime_type)
+		return FALSE;
+
+	reg = e_mail_formatter_get_extension_registry (formatter);
+	formatters = e_mail_extension_registry_get_for_mime_type (
+			reg, as_mime_type);
+	if (!formatters) {
+		formatters = e_mail_extension_registry_get_fallback (
+			reg, as_mime_type);
+	}
+
+	ok = FALSE;
+
+	d(printf("(%d) Formatting for part %s of type %s (found %d formatters)\n",
+		 _call_i, part->id, as_mime_type,
+		 formatters ? g_queue_get_length (formatters) : 0));
+
+	if (formatters) {
+		for (iter = formatters->head; iter; iter = iter->next) {
+
+			EMailFormatterExtension *extension;
+
+			extension = iter->data;
+			if (!extension)
+				continue;
+
+			ok = e_mail_formatter_extension_format (
+					extension, formatter, context,
+					part, stream, cancellable);
+
+			d(printf("\t(%d) trying %s...%s\n", _call_i,
+					G_OBJECT_TYPE_NAME (extension),
+				 	ok ? "OK" : "failed"));
+
+			if (ok)
+				break;
+		}
+	}
+
+	return ok;
+}
+
+/**
+ * em_format_format_text:
+ * @part: an #EMailPart to decode
+ * @formatter: an #EMailFormatter
+ * @stream: Where to write the converted text
+ * @cancellable: optional #GCancellable object, or %NULL
+ *
+ * Decode/output a part's content to @stream.
+ **/
+void
+e_mail_formatter_format_text (EMailFormatter *formatter,
+                              EMailPart *part,
+                              CamelStream *stream,
+                              GCancellable *cancellable)
+{
+	CamelStream *filter_stream;
+	CamelMimeFilter *filter;
+	const gchar *charset = NULL;
+	CamelMimeFilterWindows *windows = NULL;
+	CamelStream *mem_stream = NULL;
+	CamelDataWrapper *dw;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	dw = CAMEL_DATA_WRAPPER (part->part);
+
+	if (formatter->priv->charset) {
+		charset = formatter->priv->charset;
+	} else if (dw->mime_type
+		   && (charset = camel_content_type_param (dw->mime_type, "charset"))
+		   && g_ascii_strncasecmp(charset, "iso-8859-", 9) == 0) {
+		CamelStream *null;
+
+		/* Since a few Windows mailers like to claim they sent
+		 * out iso-8859-# encoded text when they really sent
+		 * out windows-cp125#, do some simple sanity checking
+		 * before we move on... */
+
+		null = camel_stream_null_new ();
+		filter_stream = camel_stream_filter_new (null);
+		g_object_unref (null);
+
+		windows = (CamelMimeFilterWindows *) camel_mime_filter_windows_new (charset);
+		camel_stream_filter_add (
+			CAMEL_STREAM_FILTER (filter_stream),
+			CAMEL_MIME_FILTER (windows));
+
+		camel_data_wrapper_decode_to_stream_sync (
+			dw, (CamelStream *) filter_stream, cancellable, NULL);
+		camel_stream_flush ((CamelStream *) filter_stream, cancellable, NULL);
+		g_object_unref (filter_stream);
+
+		charset = camel_mime_filter_windows_real_charset (windows);
+	} else if (charset == NULL) {
+		charset = formatter->priv->default_charset;
+	}
+
+	mem_stream = (CamelStream *) camel_stream_mem_new ();
+	filter_stream = camel_stream_filter_new (mem_stream);
+
+	if ((filter = camel_mime_filter_charset_new (charset, "UTF-8"))) {
+		camel_stream_filter_add (
+			CAMEL_STREAM_FILTER (filter_stream),
+			CAMEL_MIME_FILTER (filter));
+		g_object_unref (filter);
+	}
+
+	camel_data_wrapper_decode_to_stream_sync (
+			camel_medium_get_content ((CamelMedium *) dw),
+			(CamelStream *) filter_stream, cancellable, NULL);
+	camel_stream_flush ((CamelStream *) filter_stream, cancellable, NULL);
+	g_object_unref (filter_stream);
+
+	g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, NULL, NULL);
+
+	camel_stream_write_to_stream (
+		mem_stream, (CamelStream *) stream, cancellable, NULL);
+	camel_stream_flush ((CamelStream *) mem_stream, cancellable, NULL);
+
+	if (windows) {
+		g_object_unref (windows);
+	}
+
+	g_object_unref (mem_stream);
+}
+
+gchar *
+e_mail_formatter_get_html_header (EMailFormatter *formatter)
+{
+	return g_strdup_printf (
+		"<!DOCTYPE HTML>\n<html>\n"
+		"<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\" />\n"
+		"<title>Evolution Mail Display</title>\n"
+		"<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\" />\n"
+		"<style type=\"text/css\">\n"
+		"  table th { color: #000; font-weight: bold; }\n"
+		"</style>\n"
+		"</head><body bgcolor=\"#%06x\">",
+		e_color_to_value ((GdkColor *)
+			e_mail_formatter_get_color (
+				formatter, E_MAIL_FORMATTER_COLOR_BODY)));
+}
+
+EMailExtensionRegistry *
+e_mail_formatter_get_extension_registry (EMailFormatter *formatter)
+{
+	EMailFormatterClass * formatter_class;
+
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+	return E_MAIL_EXTENSION_REGISTRY (formatter_class->extension_registry);
+}
+
+guint32
+e_mail_formatter_get_text_format_flags (EMailFormatter *formatter)
+{
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), 0);
+
+	return E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags;
+}
+
+const GdkColor *
+e_mail_formatter_get_color (EMailFormatter *formatter,
+                            EMailFormatterColorType type)
+{
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+	g_return_val_if_fail (type < E_MAIL_FORMATTER_NUM_COLOR_TYPES, NULL);
+
+	return &E_MAIL_FORMATTER_GET_CLASS (formatter)->colors[type];
+}
+
+void
+e_mail_formatter_set_color (EMailFormatter *formatter,
+                            EMailFormatterColorType type,
+                            const GdkColor *color)
+{
+	GdkColor *format_color;
+	const gchar *property_name;
+
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+	g_return_if_fail (type < E_MAIL_FORMATTER_NUM_COLOR_TYPES);
+	g_return_if_fail (color != NULL);
+
+	format_color = &E_MAIL_FORMATTER_GET_CLASS (formatter)->colors[type];
+
+	if (gdk_color_equal (color, format_color))
+		return;
+
+	format_color->red   = color->red;
+	format_color->green = color->green;
+	format_color->blue  = color->blue;
+
+	switch (type) {
+		case E_MAIL_FORMATTER_COLOR_BODY:
+			property_name = "body-color";
+			break;
+		case E_MAIL_FORMATTER_COLOR_CITATION:
+			property_name = "citation-color";
+			break;
+		case E_MAIL_FORMATTER_COLOR_CONTENT:
+			property_name = "content-color";
+			break;
+		case E_MAIL_FORMATTER_COLOR_FRAME:
+			property_name = "frame-color";
+			break;
+		case E_MAIL_FORMATTER_COLOR_HEADER:
+			property_name = "header-color";
+			break;
+		case E_MAIL_FORMATTER_COLOR_TEXT:
+			property_name = "text-color";
+			break;
+		default:
+			g_return_if_reached ();
+	}
+
+	g_object_notify (G_OBJECT (formatter), property_name);
+}
+
+void
+e_mail_formatter_set_style (EMailFormatter *formatter,
+                            GtkStyle *style,
+                            GtkStateType state)
+{
+	EMailFormatterClass *formatter_class;
+
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+	g_return_if_fail (GTK_IS_STYLE (style));
+
+	formatter_class = E_MAIL_FORMATTER_GET_CLASS (formatter);
+	g_return_if_fail (formatter_class->set_style != NULL);
+
+	formatter_class->set_style (formatter, style, state);
+}
+
+EMailImageLoadingPolicy
+e_mail_formatter_get_image_loading_policy (EMailFormatter *formatter)
+{
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), 0);
+
+	return formatter->priv->image_loading_policy;
+}
+
+void
+e_mail_formatter_set_image_loading_policy (EMailFormatter *formatter,
+                                           EMailImageLoadingPolicy policy)
+{
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+	if (policy == formatter->priv->image_loading_policy)
+		return;
+
+	formatter->priv->image_loading_policy = policy;
+
+	g_object_notify (G_OBJECT (formatter), "image-loading-policy");
+}
+
+gboolean
+e_mail_formatter_get_mark_citations (EMailFormatter *formatter)
+{
+	guint32 flags;
+
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+
+	flags = E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags;
+
+	return ((flags & CAMEL_MIME_FILTER_TOHTML_MARK_CITATION) != 0);
+}
+
+void
+e_mail_formatter_set_mark_citations (EMailFormatter *formatter,
+                                     gboolean mark_citations)
+{
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+	if (mark_citations)
+		E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags |=
+			CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+	else
+		E_MAIL_FORMATTER_GET_CLASS (formatter)->text_html_flags &=
+			~CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+
+	g_object_notify (G_OBJECT (formatter), "mark-citations");
+}
+
+gboolean
+e_mail_formatter_get_only_local_photos (EMailFormatter *formatter)
+{
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+
+	return formatter->priv->only_local_photos;
+}
+
+void
+e_mail_formatter_set_only_local_photos (EMailFormatter *formatter,
+                                        gboolean only_local_photos)
+{
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+	formatter->priv->only_local_photos = only_local_photos;
+
+	g_object_notify (G_OBJECT (formatter), "only-local-photos");
+}
+
+gboolean
+e_mail_formatter_get_show_sender_photo (EMailFormatter *formatter)
+{
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+
+	return formatter->priv->show_sender_photo;
+}
+
+void
+e_mail_formatter_set_show_sender_photo (EMailFormatter *formatter,
+                                        gboolean show_sender_photo)
+{
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+	formatter->priv->show_sender_photo = show_sender_photo;
+
+	g_object_notify (G_OBJECT (formatter), "show-sender-photo");
+}
+
+gboolean
+e_mail_formatter_get_show_real_date (EMailFormatter *formatter)
+{
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+
+	return formatter->priv->show_real_date;
+}
+
+void
+e_mail_formatter_set_show_real_date (EMailFormatter *formatter,
+                                     gboolean show_real_date)
+{
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+	formatter->priv->show_real_date = show_real_date;
+
+	g_object_notify (G_OBJECT (formatter), "show-real-date");
+}
+
+gboolean
+e_mail_formatter_get_animate_images (EMailFormatter *formatter)
+{
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), FALSE);
+
+	return formatter->priv->animate_images;
+}
+
+void
+e_mail_formatter_set_animate_images (EMailFormatter *formatter,
+                                     gboolean animate_images)
+{
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+	formatter->priv->animate_images = animate_images;
+
+	g_object_notify (G_OBJECT (formatter), "animate-images");
+}
+
+const gchar *
+e_mail_formatter_get_charset (EMailFormatter *formatter)
+{
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+	return formatter->priv->charset;
+}
+
+void
+e_mail_formatter_set_charset (EMailFormatter *formatter,
+                              const gchar *charset)
+{
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+	g_return_if_fail (charset && *charset);
+
+	if (formatter->priv->charset)
+		g_free (formatter->priv->charset);
+
+	formatter->priv->charset = g_strdup (charset);
+
+	g_object_notify (G_OBJECT (formatter), "charset");
+}
+
+const gchar *
+e_mail_formatter_get_default_charset (EMailFormatter *formatter)
+{
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+	return formatter->priv->default_charset;
+}
+
+void
+e_mail_formatter_set_default_charset (EMailFormatter *formatter,
+                                      const gchar *default_charset)
+{
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+	g_return_if_fail (default_charset && *default_charset);
+
+	if (formatter->priv->default_charset)
+		g_free (formatter->priv->default_charset);
+
+	formatter->priv->default_charset = g_strdup (default_charset);
+
+	g_object_notify (G_OBJECT (formatter), "default-charset");
+}
+
+/* note: also copied in em-mailer-prefs.c */
+static const struct {
+	const gchar *name;
+	guint32 flags;
+} default_headers[] = {
+	{ N_("From"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+	{ N_("Reply-To"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+	{ N_("To"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+	{ N_("Cc"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+	{ N_("Bcc"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+	{ N_("Subject"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+	{ N_("Date"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+	{ N_("Newsgroups"), E_MAIL_FORMATTER_HEADER_FLAG_BOLD },
+	{ N_("Face"), 0 },
+};
+
+/**
+ * e_mail_formatter_get_headers:
+ * @formatter: an #EMailFormatter
+ *
+ * Returns list of currently set headers.
+ *
+ * Return Value: A #GQueue of headers which you should not modify or unref
+ */
+const GQueue *
+e_mail_formatter_get_headers (EMailFormatter *formatter)
+{
+	g_return_val_if_fail (E_IS_MAIL_FORMATTER (formatter), NULL);
+
+	return formatter->priv->header_list;
+}
+
+/**
+ * e_mail_formatter_clear_headers:
+ * @formatter: an #EMailFormatter
+ *
+ * Clear the list of headers to be displayed.  This will force all headers to
+ * be shown.
+ **/
+void
+e_mail_formatter_clear_headers (EMailFormatter *formatter)
+{
+	EMailFormatterHeader *header;
+
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+	while ((header = g_queue_pop_head (formatter->priv->header_list)) != NULL) {
+		e_mail_formatter_header_free (header);
+	}
+}
+
+/**
+ * e_mail_formatter_set_default_headers:
+ * @formatter: an #EMailFormatter
+ *
+ * Clear the list of headers and sets the default ones, e.g. "To", "From", "Cc"
+ * "Subject", etc...
+ */
+void
+e_mail_formatter_set_default_headers (EMailFormatter *formatter)
+{
+	gint ii;
+
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+	/* Set the default headers */
+	e_mail_formatter_clear_headers (formatter);
+	for (ii = 0; ii < G_N_ELEMENTS (default_headers); ii++) {
+		e_mail_formatter_add_header (
+			formatter, default_headers[ii].name, NULL,
+			default_headers[ii].flags);
+	}
+}
+
+/**
+ * e_mail_formatter_add_header:
+ * @formatter:
+ * @name: The name of the header, as it will appear during output.
+ * @value: Value of the header. Can be %NULL.
+ * @flags: EM_FORMAT_HEAD_* defines to control display attributes.
+ *
+ * Add a specific header to show.  If any headers are set, they will
+ * be displayed in the order set by this function.  Certain known
+ * headers included in this list will be shown using special
+ * formatting routines.
+ **/
+void
+e_mail_formatter_add_header (EMailFormatter *formatter,
+                             const gchar *name,
+                             const gchar *value,
+                             guint32 flags)
+{
+	EMailFormatterHeader *h;
+
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+	g_return_if_fail (name && *name);
+
+	h = e_mail_formatter_header_new (name, value);
+	h->flags = flags;
+	g_queue_push_tail (formatter->priv->header_list, h);
+}
+
+void
+e_mail_formatter_add_header_struct (EMailFormatter *formatter,
+                                    const EMailFormatterHeader *header)
+{
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+	g_return_if_fail (header && header->name);
+
+	e_mail_formatter_add_header (formatter, header->name, header->value, header->flags);
+}
+
+void e_mail_formatter_remove_header (EMailFormatter *formatter,
+				     const gchar *name,
+				     const gchar *value)
+{
+	GList *iter = NULL;
+
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+	g_return_if_fail (name && *name);
+
+	iter = g_queue_peek_head_link (formatter->priv->header_list);
+	while (iter) {
+		EMailFormatterHeader *header = iter->data;
+
+		if (!header->value || !*header->value) {
+			GList *next = iter->next;
+			if (g_strcmp0 (name, header->name) == 0)
+				g_queue_delete_link (formatter->priv->header_list, iter);
+
+			iter = next;
+			continue;
+		}
+
+		if (value && *value) {
+			if ((g_strcmp0 (name, header->name) == 0) &&
+			    (g_strcmp0 (value, header->value) == 0))
+				break;
+		} else {
+			if (g_strcmp0 (name, header->name) == 0)
+				break;
+		}
+
+		iter = iter->next;
+	}
+
+	if (iter) {
+		e_mail_formatter_header_free (iter->data);
+		g_queue_delete_link (formatter->priv->header_list, iter);
+	}
+}
+
+void
+e_mail_formatter_remove_header_struct (EMailFormatter *formatter,
+                                       const EMailFormatterHeader *header)
+{
+	g_return_if_fail (header != NULL);
+
+	e_mail_formatter_remove_header (formatter, header->name, header->value);
+}
+
+EMailFormatterHeader *
+e_mail_formatter_header_new (const gchar *name,
+                             const gchar *value)
+{
+	EMailFormatterHeader *header;
+
+	g_return_val_if_fail (name && *name, NULL);
+
+	header = g_new0 (EMailFormatterHeader, 1);
+	header->name = g_strdup (name);
+	if (value && *value)
+		header->value = g_strdup (value);
+
+	return header;
+}
+
+void
+e_mail_formatter_header_free (EMailFormatterHeader *header)
+{
+	g_return_if_fail (header);
+
+	if (header->name) {
+		g_free (header->name);
+		header->name = NULL;
+	}
+
+	if (header->value) {
+		g_free (header->value);
+		header->value = NULL;
+	}
+
+	g_free (header);
+}
diff --git a/em-format/e-mail-formatter.h b/em-format/e-mail-formatter.h
new file mode 100644
index 0000000..aea1843
--- /dev/null
+++ b/em-format/e-mail-formatter.h
@@ -0,0 +1,266 @@
+/*
+ * e-mail-formatter.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FORMATTER_H_
+#define E_MAIL_FORMATTER_H_
+
+#include <em-format/e-mail-part-list.h>
+#include <em-format/e-mail-extension-registry.h>
+#include <gdk/gdk.h>
+#include <libemail-engine/e-mail-enums.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_FORMATTER \
+	(e_mail_formatter_get_type ())
+#define E_MAIL_FORMATTER(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_FORMATTER, EMailFormatter))
+#define E_MAIL_FORMATTER_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_FORMATTER, EMailFormatterClass))
+#define E_IS_MAIL_FORMATTER(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_FORMATTER))
+#define E_IS_MAIL_FORMATTER_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_FORMATTER))
+#define E_MAIL_FORMATTER_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_FORMATTER, EMailFormatterClass))
+
+G_BEGIN_DECLS;
+
+typedef enum {
+	E_MAIL_FORMATTER_MODE_INVALID			= -1,
+	E_MAIL_FORMATTER_MODE_NORMAL			= 0,
+	E_MAIL_FORMATTER_MODE_SOURCE,
+	E_MAIL_FORMATTER_MODE_RAW,
+	E_MAIL_FORMATTER_MODE_PRINTING,
+	E_MAIL_FORMATTER_MODE_ALL_HEADERS
+} EMailFormatterMode;
+
+typedef enum {
+	E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE	= 1 << 0,
+	E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED		= 1 << 1,
+	E_MAIL_FORMATTER_HEADER_FLAG_HTML		= 1 << 2,
+	E_MAIL_FORMATTER_HEADER_FLAG_NOCOLUMNS		= 1 << 3,
+	E_MAIL_FORMATTER_HEADER_FLAG_BOLD		= 1 << 4,
+	E_MAIL_FORMATTER_HEADER_FLAG_NODEC		= 1 << 5,
+	E_MAIL_FORMATTER_HEADER_FLAG_HIDDEN		= 1 << 6,
+	E_MAIL_FORMATTER_HEADER_FLAG_NOLINKS		= 1 << 7,
+	E_MAIL_FORMATTER_HEADER_FLAG_NOELIPSIZE		= 1 << 8
+} EMailFormatterHeaderFlags;
+
+typedef enum {
+	E_MAIL_FORMATTER_COLOR_BODY,		/* header area background */
+	E_MAIL_FORMATTER_COLOR_CITATION,	/* citation font color */
+	E_MAIL_FORMATTER_COLOR_CONTENT,		/* message area background */
+	E_MAIL_FORMATTER_COLOR_FRAME,		/* frame around message area */
+	E_MAIL_FORMATTER_COLOR_HEADER,		/* header font color */
+	E_MAIL_FORMATTER_COLOR_TEXT,		/* message font color */
+	E_MAIL_FORMATTER_NUM_COLOR_TYPES
+} EMailFormatterColorType;
+
+typedef struct _EMailFormatter EMailFormatter;
+typedef struct _EMailFormatterClass EMailFormatterClass;
+typedef struct _EMailFormatterPrivate EMailFormatterPrivate;
+typedef struct _EMailFormatterHeader EMailFormatterHeader;
+typedef struct _EMailFormatterContext EMailFormatterContext;
+
+struct _EMailFormatterHeader {
+	guint32 flags;		/* E_MAIL_FORMATTER_HEADER_FLAG_ * */
+	gchar *name;
+	gchar *value;
+};
+
+struct _EMailFormatterContext {
+	CamelMimeMessage *message;
+	CamelFolder *folder;
+	gchar *message_uid;
+	GSList *parts;
+
+	EMailFormatterMode mode;
+	guint32 flags;
+};
+
+struct _EMailFormatter {
+	GObject parent;
+	EMailFormatterPrivate *priv;
+};
+
+struct _EMailFormatterClass {
+	GObjectClass parent_class;
+
+	EMailFormatterExtensionRegistry *extension_registry;
+	guint32 text_html_flags;
+
+	/* Colors should apply globally */
+	GdkColor colors[E_MAIL_FORMATTER_NUM_COLOR_TYPES];
+
+	void			(*run)			(EMailFormatter *formatter,
+							 EMailFormatterContext *context,
+							 CamelStream *stream,
+							 GCancellable *cancellable);
+
+	EMailFormatterContext *	(*create_context)	(EMailFormatter *formatter);
+
+	void			(*free_context)		(EMailFormatter *formatter,
+							 EMailFormatterContext *context);
+
+	void			(*set_style)		(EMailFormatter *formatter,
+							 GtkStyle *style,
+							 GtkStateType state);
+
+};
+
+GType		e_mail_formatter_get_type	(void);
+
+EMailFormatter *
+		e_mail_formatter_new		(void);
+
+void		e_mail_formatter_format_sync	(EMailFormatter *formatter,
+						 EMailPartList *parts_list,
+						 CamelStream *stream,
+						 guint32 flags,
+						 EMailFormatterMode mode,
+						 GCancellable *cancellable);
+
+void		e_mail_formatter_format		(EMailFormatter *formatter,
+						 EMailPartList *parts_list,
+						 CamelStream *stream,
+						 guint32 flags,
+						 EMailFormatterMode mode,
+						 GAsyncReadyCallback callback,
+						 GCancellable *cancellable,
+						 gpointer user_data);
+
+CamelStream *	e_mail_formatter_format_finished
+						(EMailFormatter *formatter,
+						 GAsyncResult *result,
+						 GError *error);
+
+gboolean	e_mail_formatter_format_as	(EMailFormatter *formatter,
+						 EMailFormatterContext *context,
+						 EMailPart *part,
+						 CamelStream *stream,
+						 const gchar *as_mime_type,
+						 GCancellable *cancellable);
+
+void		e_mail_formatter_format_text	(EMailFormatter *formatter,
+						 EMailPart *part,
+						 CamelStream *stream,
+						 GCancellable *cancellable);
+gchar *		e_mail_formatter_get_html_header
+						(EMailFormatter *formatter);
+EMailExtensionRegistry *
+		e_mail_formatter_get_extension_registry
+						(EMailFormatter *formatter);
+
+guint32		e_mail_formatter_get_text_format_flags
+						(EMailFormatter *formatter);
+
+const GdkColor *
+		e_mail_formatter_get_color	(EMailFormatter *formatter,
+						 EMailFormatterColorType type);
+void		e_mail_formatter_set_color	(EMailFormatter *efh,
+						 EMailFormatterColorType type,
+						 const GdkColor *color);
+void		e_mail_formatter_set_style	(EMailFormatter *formatter,
+						 GtkStyle *style,
+						 GtkStateType state);
+
+EMailImageLoadingPolicy
+		e_mail_formatter_get_image_loading_policy
+						(EMailFormatter *formatter);
+void		e_mail_formatter_set_image_loading_policy
+						(EMailFormatter *formatter,
+						 EMailImageLoadingPolicy policy);
+
+gboolean	e_mail_formatter_get_mark_citations
+						(EMailFormatter *formatter);
+void		e_mail_formatter_set_mark_citations
+						(EMailFormatter *formatter,
+						 gboolean mark_citations);
+
+gboolean	e_mail_formatter_get_only_local_photos
+						(EMailFormatter *formatter);
+void		e_mail_formatter_set_only_local_photos
+						(EMailFormatter *formatter,
+						 gboolean only_local_photos);
+
+gboolean	e_mail_formatter_get_show_sender_photo
+						(EMailFormatter *formatter);
+void		e_mail_formatter_set_show_sender_photo
+						(EMailFormatter *formatter,
+						 gboolean show_sender_photo);
+
+gboolean        e_mail_formatter_get_animate_images
+                                                (EMailFormatter *formatter);
+void            e_mail_formatter_set_animate_images
+                                                (EMailFormatter *formatter,
+                                                 gboolean animate_images);
+
+gboolean	e_mail_formatter_get_show_real_date
+						(EMailFormatter *formatter);
+void		e_mail_formatter_set_show_real_date
+						(EMailFormatter *formatter,
+						 gboolean show_real_date);
+
+const gchar *	e_mail_formatter_get_charset	(EMailFormatter *formatter);
+void		e_mail_formatter_set_charset	(EMailFormatter *formatter,
+						 const gchar *charset);
+
+const gchar *	e_mail_formatter_get_default_charset
+						(EMailFormatter *formatter);
+void		e_mail_formatter_set_default_charset
+						(EMailFormatter *formatter,
+						 const gchar *charset);
+
+const GQueue *	e_mail_formatter_get_headers	(EMailFormatter *formatter);
+
+void		e_mail_formatter_clear_headers	(EMailFormatter *formatter);
+
+void		e_mail_formatter_set_default_headers
+						(EMailFormatter *formatter);
+
+void		e_mail_formatter_add_header	(EMailFormatter *formatter,
+						 const gchar *name,
+						 const gchar *value,
+						 guint32 flags);
+
+void		e_mail_formatter_add_header_struct
+						(EMailFormatter *formatter,
+						 const EMailFormatterHeader *header);
+
+void		e_mail_formatter_remove_header	(EMailFormatter *formatter,
+						 const gchar *name,
+						 const gchar *value);
+
+void		e_mail_formatter_remove_header_struct
+						(EMailFormatter *formatter,
+						 const EMailFormatterHeader *header);
+
+EMailFormatterHeader *
+		e_mail_formatter_header_new	(const gchar *name,
+						 const gchar *value);
+
+void		e_mail_formatter_header_free	(EMailFormatterHeader *header);
+
+G_END_DECLS
+
+#endif /* E_MAIL_FORMATTER_H_ */
diff --git a/em-format/em-inline-filter.c b/em-format/e-mail-inline-filter.c
similarity index 92%
rename from em-format/em-inline-filter.c
rename to em-format/e-mail-inline-filter.c
index f709151..aa65708 100644
--- a/em-format/em-inline-filter.c
+++ b/em-format/e-mail-inline-filter.c
@@ -26,13 +26,12 @@
 
 #include <string.h>
 
-#include "em-inline-filter.h"
-
-#include "em-format/em-format.h"
+#include "e-mail-inline-filter.h"
+#include "e-mail-part-utils.h"
 
 #define d(x)
 
-G_DEFINE_TYPE (EMInlineFilter, em_inline_filter, CAMEL_TYPE_MIME_FILTER)
+G_DEFINE_TYPE (EMailInlineFilter, e_mail_inline_filter, CAMEL_TYPE_MIME_FILTER)
 
 enum {
 	EMIF_PLAIN,
@@ -95,7 +94,7 @@ construct_part_from_stream (CamelStream *mem,
 }
 
 static void
-inline_filter_add_part (EMInlineFilter *emif,
+inline_filter_add_part (EMailInlineFilter *emif,
                         const gchar *data,
                         gint len)
 {
@@ -186,7 +185,7 @@ inline_filter_add_part (EMInlineFilter *emif,
 
 	/* pre-snoop the mime type of unknown objects, and poke and hack it into place */
 	if (camel_content_type_is(dw->mime_type, "application", "octet-stream")
-	    && (mimetype = em_format_snoop_type (part))
+	    && (mimetype = e_mail_part_snoop_type (part))
 	    && strcmp(mimetype, "application/octet-stream") != 0) {
 		camel_data_wrapper_set_mime_type (dw, mimetype);
 		camel_mime_part_set_content_type (part, mimetype);
@@ -206,7 +205,7 @@ inline_filter_scan (CamelMimeFilter *f,
                     gsize len,
                     gint final)
 {
-	EMInlineFilter *emif = (EMInlineFilter *) f;
+	EMailInlineFilter *emif = (EMailInlineFilter *) f;
 	gchar *inptr = in, *inend = in + len;
 	gchar *data_start = in;
 	gchar *start = in;
@@ -323,7 +322,7 @@ inline_filter_scan (CamelMimeFilter *f,
 static void
 inline_filter_finalize (GObject *object)
 {
-	EMInlineFilter *emif = EM_INLINE_FILTER (object);
+	EMailInlineFilter *emif = E_MAIL_INLINE_FILTER (object);
 
 	if (emif->base_type)
 		camel_content_type_unref (emif->base_type);
@@ -333,7 +332,7 @@ inline_filter_finalize (GObject *object)
 	g_free (emif->filename);
 
 	/* Chain up to parent's finalize() method. */
-	G_OBJECT_CLASS (em_inline_filter_parent_class)->finalize (object);
+	G_OBJECT_CLASS (e_mail_inline_filter_parent_class)->finalize (object);
 }
 
 static void
@@ -371,7 +370,7 @@ inline_filter_complete (CamelMimeFilter *filter,
 static void
 inline_filter_reset (CamelMimeFilter *filter)
 {
-	EMInlineFilter *emif = EM_INLINE_FILTER (filter);
+	EMailInlineFilter *emif = E_MAIL_INLINE_FILTER (filter);
 	GSList *l;
 
 	l = emif->parts;
@@ -389,7 +388,7 @@ inline_filter_reset (CamelMimeFilter *filter)
 }
 
 static void
-em_inline_filter_class_init (EMInlineFilterClass *class)
+e_mail_inline_filter_class_init (EMailInlineFilterClass *class)
 {
 	GObjectClass *object_class;
 	CamelMimeFilterClass *mime_filter_class;
@@ -404,7 +403,7 @@ em_inline_filter_class_init (EMInlineFilterClass *class)
 }
 
 static void
-em_inline_filter_init (EMInlineFilter *emif)
+e_mail_inline_filter_init (EMailInlineFilter *emif)
 {
 	emif->data = g_byte_array_new ();
 	emif->found_any = FALSE;
@@ -423,13 +422,13 @@ em_inline_filter_init (EMInlineFilter *emif)
  *
  * Return value:
  **/
-EMInlineFilter *
-em_inline_filter_new (CamelTransferEncoding base_encoding,
-                      CamelContentType *base_type)
+EMailInlineFilter *
+e_mail_inline_filter_new (CamelTransferEncoding base_encoding,
+                          CamelContentType *base_type)
 {
-	EMInlineFilter *emif;
+	EMailInlineFilter *emif;
 
-	emif = g_object_new (EM_TYPE_INLINE_FILTER, NULL);
+	emif = g_object_new (E_TYPE_MAIL_INLINE_FILTER, NULL);
 	emif->base_encoding = base_encoding;
 	if (base_type) {
 		emif->base_type = base_type;
@@ -440,7 +439,7 @@ em_inline_filter_new (CamelTransferEncoding base_encoding,
 }
 
 CamelMultipart *
-em_inline_filter_get_multipart (EMInlineFilter *emif)
+e_mail_inline_filter_get_multipart (EMailInlineFilter *emif)
 {
 	GSList *l = emif->parts;
 	CamelMultipart *mp;
@@ -455,7 +454,7 @@ em_inline_filter_get_multipart (EMInlineFilter *emif)
 }
 
 gboolean
-em_inline_filter_found_any (EMInlineFilter *emif)
+e_mail_inline_filter_found_any (EMailInlineFilter *emif)
 {
 	g_return_val_if_fail (emif != NULL, FALSE);
 
diff --git a/em-format/em-inline-filter.h b/em-format/e-mail-inline-filter.h
similarity index 54%
rename from em-format/em-inline-filter.h
rename to em-format/e-mail-inline-filter.h
index 503ec7c..ff8248c 100644
--- a/em-format/em-inline-filter.h
+++ b/em-format/e-mail-inline-filter.h
@@ -21,36 +21,36 @@
  *
  */
 
-#ifndef EM_INLINE_FILTER_H
-#define EM_INLINE_FILTER_H
+#ifndef E_MAIL_INLINE_FILTER_H
+#define E_MAIL_INLINE_FILTER_H
 
 #include <camel/camel.h>
 
 /* Standard GObject macros */
-#define EM_TYPE_INLINE_FILTER \
-	(em_inline_filter_get_type ())
-#define EM_INLINE_FILTER(obj) \
+#define E_TYPE_MAIL_INLINE_FILTER \
+	(e_mail_inline_filter_get_type ())
+#define E_MAIL_INLINE_FILTER(obj) \
 	(G_TYPE_CHECK_INSTANCE_CAST \
-	((obj), EM_TYPE_INLINE_FILTER, EMInlineFilter))
-#define EM_INLINE_FILTER_CLASS(cls) \
+	((obj), E_TYPE_MAIL_INLINE_FILTER, EMailInlineFilter))
+#define E_MAIL_INLINE_FILTER_CLASS(cls) \
 	(G_TYPE_CHECK_CLASS_CAST \
-	((cls), EM_TYPE_INLINE_FILTER, EMInlineFilterClass))
-#define EM_IS_INLINE_FILTER(obj) \
+	((cls), E_TYPE_MAIL_INLINE_FILTER, EMailInlineFilterClass))
+#define E_MAIL_IS_INLINE_FILTER(obj) \
 	(G_TYPE_CHECK_INSTANCE_TYPE \
-	((obj), EM_TYPE_INLINE_FILTER))
-#define EM_IS_INLINE_FILTER_CLASS(cls) \
+	((obj), E_TYPE_MAIL_INLINE_FILTER))
+#define E_MAIL_IS_INLINE_FILTER_CLASS(cls) \
 	(G_TYPE_CHECK_CLASS_TYPE \
-	((cls), EM_TYPE_INLINE_FILTER))
-#define EM_INLINE_FILTER_GET_CLASS(obj) \
+	((cls), E_TYPE_MAIL_INLINE_FILTER))
+#define E_MAIL_INLINE_FILTER_GET_CLASS(obj) \
 	(G_TYPE_INSTANCE_GET_CLASS \
-	((obj), EM_TYPE_INLINE_FILTER, EMInlineFilterClass))
+	((obj), E_TYPE_MAIL_INLINE_FILTER, EMailInlineFilterClass))
 
 G_BEGIN_DECLS
 
-typedef struct _EMInlineFilter EMInlineFilter;
-typedef struct _EMInlineFilterClass EMInlineFilterClass;
+typedef struct _EMailInlineFilter EMailInlineFilter;
+typedef struct _EMailInlineFilterClass EMailInlineFilterClass;
 
-struct _EMInlineFilter {
+struct _EMailInlineFilter {
 	CamelMimeFilter filter;
 
 	gint state;
@@ -65,16 +65,18 @@ struct _EMInlineFilter {
 	gboolean found_any;
 };
 
-struct _EMInlineFilterClass {
+struct _EMailInlineFilterClass {
 	CamelMimeFilterClass filter_class;
 };
 
-GType		em_inline_filter_get_type	(void);
-EMInlineFilter *em_inline_filter_new		(CamelTransferEncoding base_encoding,
+GType		e_mail_inline_filter_get_type	(void);
+EMailInlineFilter *
+		e_mail_inline_filter_new	(CamelTransferEncoding base_encoding,
 						 CamelContentType *type);
-CamelMultipart *em_inline_filter_get_multipart	(EMInlineFilter *emif);
-gboolean	em_inline_filter_found_any	(EMInlineFilter *emif);
+CamelMultipart *e_mail_inline_filter_get_multipart
+						(EMailInlineFilter *emif);
+gboolean	e_mail_inline_filter_found_any	(EMailInlineFilter *emif);
 
 G_END_DECLS
 
-#endif /* EM_INLINE_FILTER_H */
+#endif /* E_MAIL_INLINE_FILTER_H */
diff --git a/em-format/e-mail-parser-application-mbox.c b/em-format/e-mail-parser-application-mbox.c
new file mode 100644
index 0000000..c396c48
--- /dev/null
+++ b/em-format/e-mail-parser-application-mbox.c
@@ -0,0 +1,213 @@
+/*
+ * e-mail-parser-application-mbox.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserApplicationMBox {
+	GObject parent;
+} EMailParserApplicationMBox;
+
+typedef struct _EMailParserApplicationMBoxClass {
+	GObjectClass parent_class;
+} EMailParserApplicationMBoxClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserApplicationMBox,
+	e_mail_parser_application_mbox,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "application/mbox",
+					    NULL };
+
+static GSList *
+empe_app_mbox_parse (EMailParserExtension *extension,
+                     EMailParser *parser,
+                     CamelMimePart *part,
+                     GString *part_id,
+                     GCancellable *cancellable)
+{
+	CamelMimeParser *mime_parser;
+	CamelStream *mem_stream;
+	camel_mime_parser_state_t state;
+	gint old_len;
+	gint messages;
+	GSList *parts;
+	GError *error;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	/* Extract messages from the application/mbox part and
+	 * render them as a flat list of messages. */
+
+	/* XXX If the mbox has multiple messages, maybe render them
+	 *     as a multipart/digest so each message can be expanded
+	 *     or collapsed individually.
+	 *
+	 *     See attachment_handler_mail_x_uid_list() for example. */
+
+	/* XXX This is based on em_utils_read_messages_from_stream().
+	 *     Perhaps refactor that function to return an array of
+	 *     messages instead of assuming we want to append them
+	 *     to a folder? */
+
+	mime_parser = camel_mime_parser_new ();
+	camel_mime_parser_scan_from (mime_parser, TRUE);
+
+	mem_stream = camel_stream_mem_new ();
+	camel_data_wrapper_decode_to_stream_sync (
+		camel_medium_get_content (CAMEL_MEDIUM (part)),
+		mem_stream, NULL, NULL);
+	g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, cancellable, NULL);
+
+	error =  NULL;
+	camel_mime_parser_init_with_stream (mime_parser, mem_stream, &error);
+	if (error) {
+		parts = e_mail_parser_error (parser, cancellable,
+				_("Error parsing MBOX part: %s"),
+				error->message ?
+					error->message :
+					_("Unknown error"));
+		g_clear_error (&error);
+		g_object_unref (mem_stream);
+		g_object_unref (mime_parser);
+		return parts;
+	}
+
+	g_object_unref (mem_stream);
+
+	old_len = part_id->len;
+
+	/* Extract messages from the mbox. */
+	messages = 0;
+	state = camel_mime_parser_step (mime_parser, NULL, NULL);
+
+	parts = NULL;
+	while (state == CAMEL_MIME_PARSER_STATE_FROM) {
+		CamelMimeMessage *message;
+		CamelMimePart *opart;
+		GSList *new_parts;
+
+		message = camel_mime_message_new ();
+		opart = CAMEL_MIME_PART (message);
+
+		if (!camel_mime_part_construct_from_parser_sync (
+			opart, mime_parser, NULL, NULL)) {
+			g_object_unref (message);
+			break;
+		}
+
+		g_string_append_printf (part_id, ".mbox.%d", messages);
+
+		new_parts = e_mail_parser_parse_part_as (
+				parser, CAMEL_MIME_PART (message),
+				part_id, "message/rfc822", cancellable);
+
+		/* Wrap every message as attachment */
+		new_parts = e_mail_parser_wrap_as_attachment (
+				parser, CAMEL_MIME_PART (message),
+				new_parts, part_id, cancellable);
+
+		/* Inline all messages in mbox */
+		if (new_parts && new_parts->data) {
+			EMailPart *p = new_parts->data;
+
+			p->force_inline = TRUE;
+		}
+
+		parts = g_slist_concat (parts, new_parts);
+
+		g_string_truncate (part_id, old_len);
+
+		g_object_unref (message);
+
+		/* Skip past CAMEL_MIME_PARSER_STATE_FROM_END. */
+		camel_mime_parser_step (mime_parser, NULL, NULL);
+
+		state = camel_mime_parser_step (mime_parser, NULL, NULL);
+
+		messages++;
+	}
+
+	g_object_unref (mime_parser);
+
+	return parts;
+}
+
+static guint32
+empe_app_mbox_get_flags (EMailParserExtension *extension)
+{
+	return E_MAIL_PARSER_EXTENSION_INLINE |
+		E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE;
+}
+
+static const gchar **
+empe_app_mbox_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_application_mbox_class_init (EMailParserApplicationMBoxClass *klass)
+{
+	e_mail_parser_application_mbox_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *interface)
+{
+	interface->parse = empe_app_mbox_parse;
+	interface->get_flags = empe_app_mbox_get_flags;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *interface)
+{
+	interface->mime_types = empe_app_mbox_mime_types;
+}
+
+static void
+e_mail_parser_application_mbox_init (EMailParserApplicationMBox *self)
+{
+}
diff --git a/em-format/e-mail-parser-application-smime.c b/em-format/e-mail-parser-application-smime.c
new file mode 100644
index 0000000..12bce2f
--- /dev/null
+++ b/em-format/e-mail-parser-application-smime.c
@@ -0,0 +1,199 @@
+/*
+ * e-mail-parser-application-xpkcs7mime.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserApplicationSMIME {
+	GObject parent;
+} EMailParserApplicationSMIME;
+
+typedef struct _EMailParserAppplicationSMIMEClass {
+	GObjectClass parent_class;
+} EMailParserApplicationSMIMEClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserApplicationSMIME,
+	e_mail_parser_application_smime,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "application/xpkcs7mime",
+					    "application/x-pkcs7-mime",
+					    "application/pkcs7-mime",
+					    "application/pkcs7-signature",
+					    "application/xpkcs7-signature",
+					    NULL };
+
+static GSList *
+empe_app_smime_parse (EMailParserExtension *extension,
+                       EMailParser *parser,
+                       CamelMimePart *part,
+                       GString *part_id,
+                       GCancellable *cancellable)
+{
+	CamelCipherContext *context;
+	CamelMimePart *opart;
+	CamelCipherValidity *valid;
+	GError *local_error = NULL;
+	GSList *parts, *iter;
+	CamelContentType *ct;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	ct = camel_mime_part_get_content_type (part);
+	if (camel_content_type_is (ct, "application", "pkcs7-signature") ||
+	    camel_content_type_is (ct, "application", "xpkcs7-signature")) {
+		return g_slist_alloc ();
+	}
+
+	context = camel_smime_context_new (e_mail_parser_get_session (parser));
+
+	opart = camel_mime_part_new ();
+	valid = camel_cipher_context_decrypt_sync (
+			context, part, opart,
+			cancellable, &local_error);
+
+	e_mail_part_preserve_charset_in_content_type (part, opart);
+
+	if (valid == NULL) {
+		parts = e_mail_parser_error (
+			parser, cancellable,
+			_("Could not parse S/MIME message: %s"),
+			local_error->message ?
+				local_error->message :
+				_("Unknown error"));
+		g_clear_error (&local_error);
+	} else {
+		gint len = part_id->len;
+
+		g_string_append (part_id, ".encrypted");
+
+		parts = e_mail_parser_parse_part (
+			parser, opart, part_id, cancellable);
+
+		g_string_truncate (part_id, len);
+
+		/* Update validity flags of all the involved subp-arts */
+		for (iter = parts; iter; iter = iter->next) {
+
+			EMailPart *mail_part = iter->data;
+			if (!mail_part)
+				continue;
+
+			e_mail_part_update_validity (mail_part, valid,
+				E_MAIL_PART_VALIDITY_ENCRYPTED |
+				E_MAIL_PART_VALIDITY_SMIME);
+
+		}
+
+		/* Add a widget with details about the encryption, but only when
+		 * the encrypted isn't itself secured, in that case it has created
+		 * the button itself */
+		if (!e_mail_part_is_secured (opart)) {
+			GSList *button;
+			EMailPart *mail_part;
+			g_string_append (part_id, ".encrypted.button");
+
+			button = e_mail_parser_parse_part_as (
+					parser, part, part_id,
+					"application/vnd.evolution.widget.secure-button",
+					cancellable);
+			if (button && button->data) {
+				mail_part = button->data;
+
+				e_mail_part_update_validity (mail_part, valid,
+					E_MAIL_PART_VALIDITY_ENCRYPTED |
+					E_MAIL_PART_VALIDITY_SMIME);
+			}
+
+			parts = g_slist_concat (parts, button);
+
+			g_string_truncate (part_id, len);
+		}
+
+		camel_cipher_validity_free (valid);
+	}
+
+	g_object_unref (opart);
+	g_object_unref (context);
+
+	return parts;
+}
+
+static guint32
+empe_app_smime_get_flags (EMailParserExtension *extension)
+{
+	return E_MAIL_PARSER_EXTENSION_INLINE;
+}
+
+static const gchar **
+empe_application_smime_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_application_smime_class_init (EMailParserApplicationSMIMEClass *klass)
+{
+	e_mail_parser_application_smime_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *interface)
+{
+	interface->parse = empe_app_smime_parse;
+	interface->get_flags = empe_app_smime_get_flags;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *interface)
+{
+	interface->mime_types = empe_application_smime_mime_types;
+}
+
+static void
+e_mail_parser_application_smime_init (EMailParserApplicationSMIME *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-attachment-bar.c b/em-format/e-mail-parser-attachment-bar.c
new file mode 100644
index 0000000..009869d
--- /dev/null
+++ b/em-format/e-mail-parser-attachment-bar.c
@@ -0,0 +1,120 @@
+/*
+ * e-mail-parser-attachment-bar.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+#include "e-mail-part-attachment-bar.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <e-util/e-util.h>
+
+#include <widgets/misc/e-attachment-bar.h>
+
+#include <camel/camel.h>
+
+static void
+mail_part_attachment_bar_free (EMailPart *part)
+{
+	EMailPartAttachmentBar *empab = (EMailPartAttachmentBar *) part;
+
+	g_clear_object (&empab->store);
+}
+
+/******************************************************************************/
+
+typedef struct _EMailParserAttachmentBar {
+	GObject parent;
+} EMailParserAttachmentBar;
+
+typedef struct _EMailParserAttachmentBarClass {
+	GObjectClass parent_class;
+} EMailParserAttachmentBarClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserAttachmentBar,
+	e_mail_parser_attachment_bar,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init))
+
+static const gchar *parser_mime_types[] = { "application/vnd.evolution.widget.attachment-bar", NULL };
+
+static GSList *
+empe_attachment_bar_parse (EMailParserExtension *extension,
+                           EMailParser *parser,
+                           CamelMimePart *part,
+                           GString *part_id,
+                           GCancellable *cancellable)
+{
+	EMailPartAttachmentBar *empab;
+	gint len;
+
+	len = part_id->len;
+	g_string_append (part_id, ".attachment-bar");
+	empab = (EMailPartAttachmentBar *) e_mail_part_subclass_new (
+			part, part_id->str, sizeof (EMailPartAttachmentBar),
+			(GFreeFunc) mail_part_attachment_bar_free);
+	empab->parent.mime_type = g_strdup ("application/vnd.evolution.widget.attachment-bar");
+	empab->store = E_ATTACHMENT_STORE (e_attachment_store_new ());
+	g_string_truncate (part_id, len);
+
+	return g_slist_append (NULL, empab);
+}
+
+static const gchar **
+empe_attachment_bar_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_attachment_bar_class_init (EMailParserAttachmentBarClass *klass)
+{
+	e_mail_parser_attachment_bar_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_attachment_bar_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_attachment_bar_mime_types;
+}
+
+static void
+e_mail_parser_attachment_bar_init (EMailParserAttachmentBar *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-extension.c b/em-format/e-mail-parser-extension.c
new file mode 100644
index 0000000..589fae3
--- /dev/null
+++ b/em-format/e-mail-parser-extension.c
@@ -0,0 +1,101 @@
+/*
+ * e-mail-parser-extension.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <camel/camel.h>
+
+#include "e-mail-parser-extension.h"
+
+G_DEFINE_INTERFACE (
+	EMailParserExtension,
+	e_mail_parser_extension,
+	E_TYPE_MAIL_EXTENSION)
+
+/**
+ * EMailParserExtension:
+ *
+ * The #EMailParserExtension is an abstract interface for all extensions for
+ * #EMailParser.
+ */
+
+static void
+e_mail_parser_extension_default_init (EMailParserExtensionInterface *iface)
+{
+
+}
+
+/**
+ * e_mail_parser_extension_parse
+ * @extension: an #EMailParserExtension
+ * @parser: a #EMailParser
+ * @mime_part: (allow-none) a #CamelMimePart to parse
+ * @part_id: a #GString to which parser will append ID of the parsed part.
+ * @flags: #EMailParserFlags
+ * @cancellable: (allow-none) A #GCancellable
+ *
+ * A virtual function reimplemented in all mail parser extensions. The function
+ * decodes and parses the @mime_part, creating one or more #EMailPart<!-//>s.
+ *
+ * When the function is unable to parse the @mime_part (either because it's broken
+ * or because it is a different mimetype then the extension is specialized for), the
+ * function will return @NULL indicating the #EMailParser, that it should pick
+ * another extension.
+ *
+ * When the @mime_part contains for example multipart/mixed of one RFC822 message
+ * with an attachment and of one image, then parser must make sure that the
+ * returned #GSList is correctly ordered:
+ *
+ * part1.rfc822.plain_text
+ * part1.rfc822.attachment
+ * part2.image
+ *
+ * Implementation of this function must be thread-safe.
+ *
+ * Return value: Returns #GSList of #EMailPart<!-//>s when the part was succesfully
+ * parsed, returns @NULL when the parser is not able to parse the part.
+ */
+GSList *
+e_mail_parser_extension_parse (EMailParserExtension *extension,
+                              EMailParser *parser,
+                              CamelMimePart *mime_part,
+                              GString *part_id,
+                              GCancellable *cancellable)
+{
+	EMailParserExtensionInterface *interface;
+
+	g_return_val_if_fail (E_IS_MAIL_PARSER_EXTENSION (extension), NULL);
+	g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+
+	interface = E_MAIL_PARSER_EXTENSION_GET_INTERFACE (extension);
+	g_return_val_if_fail (interface->parse != NULL, NULL);
+
+	return interface->parse (extension, parser, mime_part, part_id, cancellable);
+}
+
+guint32
+e_mail_parser_extension_get_flags (EMailParserExtension *extension)
+{
+	EMailParserExtensionInterface *interface;
+
+	g_return_val_if_fail (E_IS_MAIL_PARSER_EXTENSION (extension), 0);
+
+	interface = E_MAIL_PARSER_EXTENSION_GET_INTERFACE (extension);
+	if (interface->get_flags == NULL)
+		return 0;
+
+	return interface->get_flags (extension);
+}
diff --git a/em-format/e-mail-parser-extension.h b/em-format/e-mail-parser-extension.h
new file mode 100644
index 0000000..0dcff76
--- /dev/null
+++ b/em-format/e-mail-parser-extension.h
@@ -0,0 +1,86 @@
+/*
+ * e-mail-parser-extension.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PARSER_EXTENSION_H
+#define E_MAIL_PARSER_EXTENSION_H
+
+#include <em-format/e-mail-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PARSER_EXTENSION \
+	(e_mail_parser_extension_get_type ())
+#define E_MAIL_PARSER_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_PARSER_EXTENSION, EMailParserExtension))
+#define E_MAIL_PARSER_EXTENSION_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_PARSER_EXTENSION, EMailParserExtensionInterface))
+#define E_IS_MAIL_PARSER_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_PARSER_EXTENSION))
+#define E_IS_MAIL_PARSER_EXTENSION_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_PARSER_EXTENSION))
+#define E_MAIL_PARSER_EXTENSION_GET_INTERFACE(obj) \
+	(G_TYPE_INSTANCE_GET_INTERFACE \
+	((obj), E_TYPE_MAIL_PARSER_EXTENSION, EMailParserExtensionInterface))
+
+#define EMP_EXTENSION_GET_PARSER(e) \
+	E_MAIL_PARSER (e_extension_get_extensible (E_EXTENSION (e)))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailParserExtension EMailParserExtension;
+typedef struct _EMailParserExtensionInterface EMailParserExtensionInterface;
+
+typedef enum {
+	E_MAIL_PARSER_EXTENSION_INLINE			= 1 << 0, /* Don't parse as attachment */
+	E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION	= 1 << 1, /* Always expand */
+	E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE		= 1 << 2  /* Always check what's inside */
+} EMailParserExtensionFlags;
+
+struct _EMailParserExtensionInterface {
+	EMailExtensionInterface	parent_interface;
+
+	GSList *		(*parse)	(EMailParserExtension *extension,
+					 EMailParser *parser,
+					 CamelMimePart *mime_part,
+					 GString *part_id,
+					 GCancellable *cancellable);
+
+	guint32		(*get_flags)	(EMailParserExtension *extension);
+
+};
+
+GType		e_mail_parser_extension_get_type
+						(void);
+
+GSList *		e_mail_parser_extension_parse	(EMailParserExtension *extension,
+						 EMailParser *parser,
+						 CamelMimePart *mime_part,
+						 GString *part_id,
+						 GCancellable *cancellable);
+
+guint32		e_mail_parser_extension_get_flags
+						(EMailParserExtension *extension);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PARSER_EXTENSION_H */
diff --git a/em-format/e-mail-parser-headers.c b/em-format/e-mail-parser-headers.c
new file mode 100644
index 0000000..06f2874
--- /dev/null
+++ b/em-format/e-mail-parser-headers.c
@@ -0,0 +1,112 @@
+/*
+ * e-mail-parser-headers.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <libemail-engine/e-mail-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserHeaders {
+	GObject parent;
+} EMailParserHeaders;
+
+typedef struct _EMailParserHeadersClass {
+	GObjectClass parent_class;
+} EMailParserHeadersClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserHeaders,
+	e_mail_parser_headers,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar *parser_mime_types[] = { "application/vnd.evolution.headers", NULL };
+
+static GSList *
+empe_headers_parse (EMailParserExtension *extension,
+                    EMailParser *parser,
+                    CamelMimePart *part,
+                    GString *part_id,
+                    GCancellable *cancellable)
+{
+	EMailPart *mail_part;
+	gint len;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	len = part_id->len;
+	g_string_append (part_id, ".headers");
+
+	mail_part = e_mail_part_new (part, part_id->str);
+	mail_part->mime_type = g_strdup ("application/vnd.evolution.headers");
+	g_string_truncate (part_id, len);
+
+	return g_slist_append (NULL, mail_part);
+}
+
+static const gchar **
+empe_headers_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_headers_class_init (EMailParserHeadersClass *klass)
+{
+	e_mail_parser_headers_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_headers_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_headers_mime_types;
+}
+
+static void
+e_mail_parser_headers_init (EMailParserHeaders *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-image.c b/em-format/e-mail-parser-image.c
new file mode 100644
index 0000000..2fb1fdf
--- /dev/null
+++ b/em-format/e-mail-parser-image.c
@@ -0,0 +1,147 @@
+/*
+ * e-mail-parser-image.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-part-utils.h>
+#include <em-format/e-mail-parser.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+typedef struct _EMailParserImage {
+	GObject parent;
+} EMailParserImage;
+
+typedef struct _EMailParserImageClass {
+	GObjectClass parent_class;
+} EMailParserImageClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserImage,
+	e_mail_parser_image,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar *parser_mime_types[] = { "image/gif",
+					    "image/jpeg",
+					    "image/png",
+					    "image/x-png",
+					    "image/x-bmp",
+					    "image/bmp",
+					    "image/svg",
+					    "image/x-cmu-raster",
+					    "image/x-ico",
+					    "image/x-portable-anymap",
+					    "image/x-portable-bitmap",
+					    "image/x-portable-graymap",
+					    "image/x-portable-pixmap",
+					    "image/x-xpixmap",
+					    "image/jpg",
+					    "image/pjpeg",
+					    NULL };
+
+static GSList *
+empe_image_parse (EMailParserExtension *extension,
+                  EMailParser *parser,
+                  CamelMimePart *part,
+                  GString *part_id,
+                  GCancellable *cancellable)
+{
+	EMailPart *mail_part;
+	const gchar *tmp;
+	gchar *cid;
+	gint len;
+	CamelContentType *ct;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	tmp = camel_mime_part_get_content_id (part);
+	if (tmp) {
+		cid = g_strdup_printf ("cid:%s", tmp);
+	} else {
+		cid = NULL;
+	}
+
+	len = part_id->len;
+	g_string_append (part_id, ".image");
+
+	ct = camel_mime_part_get_content_type (part);
+
+	mail_part = e_mail_part_new (part, part_id->str);
+	mail_part->is_attachment = TRUE;
+	mail_part->cid = cid;
+	mail_part->mime_type = ct ? camel_content_type_simple (ct) : g_strdup ("image/*");
+	mail_part->is_hidden = (cid != NULL);
+
+	g_string_truncate (part_id, len);
+
+	if (!cid) {
+		return e_mail_parser_wrap_as_attachment (
+			parser, part, g_slist_append (NULL, mail_part),
+			part_id, cancellable);
+	}
+
+	return g_slist_append (NULL, mail_part);
+}
+
+static const gchar **
+empe_image_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_image_class_init (EMailParserImageClass *klass)
+{
+	e_mail_parser_image_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_image_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_image_mime_types;
+}
+
+static void
+e_mail_parser_image_init (EMailParserImage *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-inlinepgp-encrypted.c b/em-format/e-mail-parser-inlinepgp-encrypted.c
new file mode 100644
index 0000000..5395b7b
--- /dev/null
+++ b/em-format/e-mail-parser-inlinepgp-encrypted.c
@@ -0,0 +1,205 @@
+/*
+ * e-mail-parser-inlinepgp-encrypted.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserInlinePGPEncrypted {
+	GObject parent;
+} EMailParserInlinePGPEncrypted;
+
+typedef struct _EMailParserInlinePGPEncryptedClass {
+	GObjectClass parent_class;
+} EMailParserInlinePGPEncryptedClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserInlinePGPEncrypted,
+	e_mail_parser_inline_pgp_encrypted,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "application/x-inlinepgp-encrypted",
+					    NULL };
+
+static GSList *
+empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
+                                EMailParser *parser,
+                                CamelMimePart *part,
+                                GString *part_id,
+                                GCancellable *cancellable)
+{
+	CamelCipherContext *cipher;
+	CamelCipherValidity *valid;
+	CamelMimePart *opart;
+	CamelDataWrapper *dw;
+	gchar *mime_type;
+	gint len;
+	GError *local_error = NULL;
+	GSList *parts, *iter;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	cipher = camel_gpg_context_new (e_mail_parser_get_session (parser));
+
+	opart = camel_mime_part_new ();
+
+	/* Decrypt the message */
+	valid = camel_cipher_context_decrypt_sync (
+		cipher, part, opart, cancellable, &local_error);
+
+	if (!valid) {
+		parts = e_mail_parser_error (
+				parser, cancellable,
+				_("Could not parse PGP message: %s"),
+				local_error->message ?
+					local_error->message :
+					_("Unknown error"));
+		g_clear_error (&local_error);
+
+		parts = g_slist_concat (parts,
+				e_mail_parser_parse_part_as (parser,
+					part, part_id,
+				 	"application/vnd.evolution.source",
+					cancellable));
+
+		g_object_unref (cipher);
+		g_object_unref (opart);
+		return parts;
+	}
+
+	dw = camel_medium_get_content ((CamelMedium *) opart);
+	mime_type = camel_data_wrapper_get_mime_type (dw);
+
+	/* this ensures to show the 'opart' as inlined, if possible */
+	if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) {
+		const gchar *snoop = e_mail_part_snoop_type (opart);
+
+		if (snoop)
+			camel_data_wrapper_set_mime_type (dw, snoop);
+	}
+
+	e_mail_part_preserve_charset_in_content_type (part, opart);
+	g_free (mime_type);
+
+	/* Pass it off to the real formatter */
+	len = part_id->len;
+	g_string_append (part_id, ".inlinepgp_encrypted");
+
+	parts = e_mail_parser_parse_part_as (
+			parser, opart, part_id,
+			camel_data_wrapper_get_mime_type (dw), cancellable);
+
+	g_string_truncate (part_id, len);
+
+	for (iter = parts; iter; iter = iter->next) {
+		EMailPart *mail_part;
+
+		mail_part = iter->data;
+		if (!mail_part)
+			continue;
+
+		e_mail_part_update_validity (mail_part, valid,
+			E_MAIL_PART_VALIDITY_ENCRYPTED |
+			E_MAIL_PART_VALIDITY_PGP);
+	}
+
+	/* Add a widget with details about the encryption, but only when
+	 * the encrypted isn't itself secured, in that case it has created
+	 * the button itself */
+	if (!e_mail_part_is_secured (opart)) {
+		GSList *button;
+		EMailPart *mail_part;
+		g_string_append (part_id, ".inlinepgp_encrypted.button");
+
+		button = e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.widget.secure-button",
+				cancellable);
+		if (button && button->data) {
+			mail_part = button->data;
+
+			e_mail_part_update_validity (mail_part, valid,
+				E_MAIL_PART_VALIDITY_ENCRYPTED |
+				E_MAIL_PART_VALIDITY_PGP);
+		}
+
+		parts = g_slist_concat (parts, button);
+
+		g_string_truncate (part_id, len);
+	}
+
+	/* Clean Up */
+	camel_cipher_validity_free (valid);
+	g_object_unref (opart);
+	g_object_unref (cipher);
+
+	return parts;
+}
+
+static const gchar **
+empe_inlinepgp_encrypted_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_inline_pgp_encrypted_class_init (EMailParserInlinePGPEncryptedClass *klass)
+{
+	e_mail_parser_inline_pgp_encrypted_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_inlinepgp_encrypted_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_inlinepgp_encrypted_mime_types;
+}
+
+static void
+e_mail_parser_inline_pgp_encrypted_init (EMailParserInlinePGPEncrypted *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-inlinepgp-signed.c b/em-format/e-mail-parser-inlinepgp-signed.c
new file mode 100644
index 0000000..d90dcdd
--- /dev/null
+++ b/em-format/e-mail-parser-inlinepgp-signed.c
@@ -0,0 +1,230 @@
+/*
+ * e-mail-parser-inlinepgp-signed.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserInlinePGPSigned {
+	GObject parent;
+} EMailParserInlinePGPSigned;
+
+typedef struct _EMailParserInlinePGPSignedClass {
+	GObjectClass parent_class;
+} EMailParserInlinePGPSignedClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserInlinePGPSigned,
+	e_mail_parser_inline_pgp_signed,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "application/x-inlinepgp-signed",
+					    NULL };
+
+static GSList *
+empe_inlinepgp_signed_parse (EMailParserExtension *extension,
+                             EMailParser *parser,
+                             CamelMimePart *part,
+                             GString *part_id,
+                             GCancellable *cancellable)
+{
+	CamelStream *filtered_stream;
+	CamelMimeFilterPgp *pgp_filter;
+	CamelContentType *content_type;
+	CamelCipherContext *cipher;
+	CamelCipherValidity *valid;
+	CamelDataWrapper *dw;
+	CamelMimePart *opart;
+	CamelStream *ostream;
+	gchar *type;
+	gint len;
+	GError *local_error = NULL;
+	GByteArray *ba;
+	GSList *parts, *iter;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	cipher = camel_gpg_context_new (e_mail_parser_get_session (parser));
+
+	/* Verify the signature of the message */
+	valid = camel_cipher_context_verify_sync (
+		cipher, part, cancellable, &local_error);
+	if (!valid) {
+		parts = e_mail_parser_error (
+				parser, cancellable,
+				_("Error verifying signature: %s"),
+				local_error->message ?
+					local_error->message :
+					_("Unknown error"));
+
+		g_clear_error (&local_error);
+
+		parts = g_slist_concat (parts,
+				e_mail_parser_parse_part_as (
+					parser, part, part_id,
+				 	"application/vnd.evolution.source",
+					cancellable));
+
+		g_object_unref (cipher);
+		return parts;
+	}
+
+	/* Setup output stream */
+	ostream = camel_stream_mem_new ();
+	filtered_stream = camel_stream_filter_new (ostream);
+
+	/* Add PGP header / footer filter */
+	pgp_filter = (CamelMimeFilterPgp *) camel_mime_filter_pgp_new ();
+	camel_stream_filter_add (
+		CAMEL_STREAM_FILTER (filtered_stream),
+		CAMEL_MIME_FILTER (pgp_filter));
+	g_object_unref (pgp_filter);
+
+	/* Pass through the filters that have been setup */
+	dw = camel_medium_get_content ((CamelMedium *) part);
+	camel_data_wrapper_decode_to_stream_sync (
+		dw, (CamelStream *) filtered_stream, cancellable, NULL);
+	camel_stream_flush ((CamelStream *) filtered_stream, cancellable, NULL);
+	g_object_unref (filtered_stream);
+
+	/* Create a new text/plain MIME part containing the signed
+	 * content preserving the original part's Content-Type params. */
+	content_type = camel_mime_part_get_content_type (part);
+	type = camel_content_type_format (content_type);
+	content_type = camel_content_type_decode (type);
+	g_free (type);
+
+	g_free (content_type->type);
+	content_type->type = g_strdup ("text");
+	g_free (content_type->subtype);
+	content_type->subtype = g_strdup ("plain");
+	type = camel_content_type_format (content_type);
+	camel_content_type_unref (content_type);
+
+	ba = camel_stream_mem_get_byte_array ((CamelStreamMem *) ostream);
+	opart = camel_mime_part_new ();
+	camel_mime_part_set_content (opart, (gchar *) ba->data, ba->len, type);
+	g_free (type);
+
+	len = part_id->len;
+	g_string_append (part_id, ".inlinepgp_signed");
+
+	parts = e_mail_parser_parse_part (
+			parser, opart, part_id, cancellable);
+
+	for (iter = parts; iter; iter = iter->next) {
+		EMailPart *mail_part;
+
+		mail_part = iter->data;
+		if (!mail_part)
+			continue;
+
+		e_mail_part_update_validity (mail_part, valid,
+			E_MAIL_PART_VALIDITY_SIGNED |
+			E_MAIL_PART_VALIDITY_PGP);
+	}
+
+	g_string_truncate (part_id, len);
+
+	/* Add a widget with details about the encryption, but only when
+	 * the encrypted isn't itself secured, in that case it has created
+	 * the button itself */
+	if (!e_mail_part_is_secured (opart)) {
+		GSList *button;
+		EMailPart *mail_part;
+		g_string_append (part_id, ".inlinepgp_signed.button");
+
+		button = e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.widget.secure-button",
+				cancellable);
+		if (button && button->data) {
+			mail_part = button->data;
+
+			e_mail_part_update_validity (mail_part, valid,
+				E_MAIL_PART_VALIDITY_SIGNED |
+				E_MAIL_PART_VALIDITY_PGP);
+		}
+
+		parts = g_slist_concat (parts, button);
+
+		g_string_truncate (part_id, len);
+	}
+
+	/* Clean Up */
+	camel_cipher_validity_free (valid);
+	g_object_unref (dw);
+	g_object_unref (opart);
+	g_object_unref (ostream);
+	g_object_unref (cipher);
+
+	return parts;
+}
+
+static const gchar **
+empe_inlinepgp_signed_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_inline_pgp_signed_class_init (EMailParserInlinePGPSignedClass *klass)
+{
+	e_mail_parser_inline_pgp_signed_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_inlinepgp_signed_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_inlinepgp_signed_mime_types;
+}
+
+static void
+e_mail_parser_inline_pgp_signed_init (EMailParserInlinePGPSigned *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-message-deliverystatus.c b/em-format/e-mail-parser-message-deliverystatus.c
new file mode 100644
index 0000000..feae7c2
--- /dev/null
+++ b/em-format/e-mail-parser-message-deliverystatus.c
@@ -0,0 +1,116 @@
+/*
+ * e-mail-parser-message-deliverystatus.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib-object.h>
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserMessageDeliveryStatus {
+	GObject parent;
+} EMailParserMessageDeliveryStatus;
+
+typedef struct _EMailParserMessageDeliveryStatusClass {
+	GObjectClass parent_class;
+} EMailParserMessageDeliveryStatusClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMessageDeliveryStatus,
+	e_mail_parser_message_delivery_status,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "message/delivery-status",
+					    NULL };
+
+static GSList *
+empe_msg_deliverystatus_parse (EMailParserExtension *extension,
+                               EMailParser *parser,
+                               CamelMimePart *part,
+                               GString *part_id,
+                               GCancellable *cancellable)
+{
+	EMailPart *mail_part;
+	gsize len;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	len = part_id->len;
+	g_string_append (part_id, ".delivery-status");
+	mail_part = e_mail_part_new (part, part_id->str);
+	mail_part->mime_type = g_strdup ("text/plain");
+
+	g_string_truncate (part_id, len);
+
+	/* The only reason for having a separate parser for
+	 * message/delivery-status is to display the part as an attachment */
+	return e_mail_parser_wrap_as_attachment (
+			parser, part, g_slist_append (NULL, mail_part),
+			part_id, cancellable);
+}
+
+static const gchar **
+empe_msg_deliverystatus_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_message_delivery_status_class_init (EMailParserMessageDeliveryStatusClass *klass)
+{
+	e_mail_parser_message_delivery_status_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_msg_deliverystatus_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_msg_deliverystatus_mime_types;
+}
+
+static void
+e_mail_parser_message_delivery_status_init (EMailParserMessageDeliveryStatus *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-message-external.c b/em-format/e-mail-parser-message-external.c
new file mode 100644
index 0000000..8c02a3e
--- /dev/null
+++ b/em-format/e-mail-parser-message-external.c
@@ -0,0 +1,211 @@
+/*
+ * e-mail-parser-message-external.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+#include <string.h>
+#include <ctype.h>
+
+typedef struct _EMailParserMessageExternal {
+	GObject parent;
+} EMailParserMessageExternal;
+
+typedef struct _EMailParserMessageExternalClass {
+	GObjectClass parent_class;
+} EMailParserMessageExternalClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMessageExternal,
+	e_mail_parser_message_external,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "message/external-body",
+					    NULL };
+
+static GSList *
+empe_msg_external_parse (EMailParserExtension *extension,
+                         EMailParser *parser,
+                         CamelMimePart *part,
+                         GString *part_id,
+                         GCancellable *cancellable)
+{
+	EMailPart *mail_part;
+	CamelMimePart *newpart;
+	CamelContentType *type;
+	const gchar *access_type;
+	gchar *url = NULL, *desc = NULL;
+	gchar *content;
+	gint len;
+	gchar *mime_type;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	newpart = camel_mime_part_new ();
+
+	/* needs to be cleaner */
+	type = camel_mime_part_get_content_type (part);
+	access_type = camel_content_type_param (type, "access-type");
+	if (!access_type) {
+		const gchar *msg = _("Malformed external-body part");
+		mime_type = g_strdup ("text/plain");
+		camel_mime_part_set_content (newpart, msg, strlen (msg), mime_type);
+		goto addPart;
+	}
+
+	if (!g_ascii_strcasecmp(access_type, "ftp") ||
+	    !g_ascii_strcasecmp(access_type, "anon-ftp")) {
+		const gchar *name, *site, *dir, *mode;
+		gchar *path;
+		gchar ftype[16];
+
+		name = camel_content_type_param (type, "name");
+		site = camel_content_type_param (type, "site");
+		dir = camel_content_type_param (type, "directory");
+		mode = camel_content_type_param (type, "mode");
+		if (name == NULL || site == NULL)
+			goto fail;
+
+		/* Generate the path. */
+		if (dir)
+			path = g_strdup_printf("/%s/%s", *dir=='/'?dir+1:dir, name);
+		else
+			path = g_strdup_printf("/%s", *name=='/'?name+1:name);
+
+		if (mode && *mode)
+			sprintf(ftype, ";type=%c",  *mode);
+		else
+			ftype[0] = 0;
+
+		url = g_strdup_printf ("ftp://%s%s%s";, site, path, ftype);
+		g_free (path);
+		desc = g_strdup_printf (_("Pointer to FTP site (%s)"), url);
+	} else if (!g_ascii_strcasecmp (access_type, "local-file")) {
+		const gchar *name, *site;
+
+		name = camel_content_type_param (type, "name");
+		site = camel_content_type_param (type, "site");
+		if (name == NULL)
+			goto fail;
+
+		url = g_filename_to_uri (name, NULL, NULL);
+		if (site)
+			desc = g_strdup_printf(_("Pointer to local file (%s) valid at site \"%s\""), name, site);
+		else
+			desc = g_strdup_printf(_("Pointer to local file (%s)"), name);
+	} else if (!g_ascii_strcasecmp (access_type, "URL")) {
+		const gchar *urlparam;
+		gchar *s, *d;
+
+		/* RFC 2017 */
+		urlparam = camel_content_type_param (type, "url");
+		if (urlparam == NULL)
+			goto fail;
+
+		/* For obscure MIMEy reasons, the URL may be split into words */
+		url = g_strdup (urlparam);
+		s = d = url;
+		while (*s) {
+			if (!isspace ((guchar) * s))
+				*d++ = *s;
+			s++;
+		}
+		*d = 0;
+		desc = g_strdup_printf (_("Pointer to remote data (%s)"), url);
+	} else {
+		goto fail;
+	}
+
+	mime_type = g_strdup ("text/html");
+	content = g_strdup_printf ("<a href=\"%s\">%s</a>", url, desc);
+	camel_mime_part_set_content (newpart, content, strlen (content), mime_type);
+	g_free (content);
+
+	g_free (url);
+	g_free (desc);
+
+	goto addPart;
+
+fail:
+	content = g_strdup_printf (
+		_("Pointer to unknown external data (\"%s\" type)"),
+		access_type);
+	mime_type = g_strdup ("text/plain");
+	camel_mime_part_set_content (newpart, content, strlen (content), mime_type);
+	g_free (content);
+
+addPart:
+	len = part_id->len;
+	g_string_append (part_id, ".msg_external");
+	mail_part = e_mail_part_new (part, part_id->str);
+	mail_part->mime_type = mime_type;
+	g_string_truncate (part_id, len);
+
+	return g_slist_append (NULL, mail_part);
+}
+
+static const gchar **
+empe_msg_external_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_message_external_class_init (EMailParserMessageExternalClass *klass)
+{
+	e_mail_parser_message_external_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_msg_external_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_msg_external_mime_types;
+}
+
+static void
+e_mail_parser_message_external_init (EMailParserMessageExternal *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-message-rfc822.c b/em-format/e-mail-parser-message-rfc822.c
new file mode 100644
index 0000000..75b0306
--- /dev/null
+++ b/em-format/e-mail-parser-message-rfc822.c
@@ -0,0 +1,174 @@
+/*
+ * e-mail-parser-message-rfc822.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+#include <glib-object.h>
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-list.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserMessageRFC822 {
+	GObject parent;
+} EMailParserMessageRFC822;
+
+typedef struct _EMailParserMessageRFC822Class {
+	GObjectClass parent_class;
+} EMailParserMessageRFC822Class;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMessageRFC822,
+	e_mail_parser_message_rfc822,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "message/rfc822",
+					    "message/news",
+					    "message/*",
+					    NULL };
+
+static GSList *
+empe_msg_rfc822_parse (EMailParserExtension *extension,
+                       EMailParser *eparser,
+                       CamelMimePart *part,
+                       GString *part_id,
+                       GCancellable *cancellable)
+{
+	GSList *parts = NULL;
+	EMailPart *mail_part;
+	gint len;
+	CamelMimePart *message;
+	CamelDataWrapper *dw;
+	CamelStream *new_stream;
+	CamelMimeParser *mime_parser;
+	CamelContentType *ct;
+
+	len = part_id->len;
+	g_string_append (part_id, ".rfc822");
+
+        /* Create an empty PURI that will represent start of the RFC message */
+	mail_part = e_mail_part_new (part, part_id->str);
+	mail_part->mime_type = g_strdup ("message/rfc822");
+	parts = g_slist_append (NULL, mail_part);
+
+	/* Sometime the _actual_ message is encapsulated in another CamelMimePart,
+	 * sometimes the CamelMimePart actually represents the RFC822 message */
+	ct = camel_mime_part_get_content_type (part);
+	if (camel_content_type_is (ct, "message", "rfc822")) {
+		new_stream = camel_stream_mem_new ();
+		mime_parser = camel_mime_parser_new ();
+		message = (CamelMimePart *) camel_mime_message_new ();
+
+		dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+		camel_data_wrapper_decode_to_stream_sync (
+			dw, new_stream, cancellable, NULL);
+		g_seekable_seek (
+			G_SEEKABLE (new_stream), 0, G_SEEK_SET, cancellable, NULL);
+		camel_mime_parser_init_with_stream (
+			mime_parser, new_stream, NULL);
+		camel_mime_part_construct_from_parser_sync (
+			message, mime_parser, cancellable, NULL);
+
+		g_object_unref (mime_parser);
+		g_object_unref (new_stream);
+	} else {
+		message = g_object_ref (part);
+	}
+
+	parts = g_slist_concat (parts, e_mail_parser_parse_part_as (
+						eparser, message, part_id,
+						"application/vnd.evolution.message",
+						cancellable));
+
+	g_object_unref (message);
+
+        /* Add another generic EMailPart that represents end of the RFC message.
+         * The em_format_write() function will skip all parts between the ".rfc822"
+         * part and ".rfc822.end" part as they will be rendered in an <iframe> */
+	g_string_append (part_id, ".end");
+	mail_part = e_mail_part_new (message, part_id->str);
+	mail_part->is_hidden = TRUE;
+	parts = g_slist_append (parts, mail_part);
+	g_string_truncate (part_id, len);
+
+	if (e_mail_part_is_attachment (message)) {
+		return e_mail_parser_wrap_as_attachment (
+			eparser, message, parts, part_id, cancellable);
+	}
+
+	return parts;
+}
+
+static guint32
+empe_msg_rfc822_get_flags (EMailParserExtension *extension)
+{
+	return E_MAIL_PARSER_EXTENSION_INLINE |
+		E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE;
+}
+
+static const gchar **
+empe_msg_rfc822_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_message_rfc822_class_init (EMailParserMessageRFC822Class *klass)
+{
+	e_mail_parser_message_rfc822_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_msg_rfc822_parse;
+	iface->get_flags = empe_msg_rfc822_get_flags;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_msg_rfc822_mime_types;
+}
+
+static void
+e_mail_parser_message_rfc822_init (EMailParserMessageRFC822 *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-message.c b/em-format/e-mail-parser-message.c
new file mode 100644
index 0000000..acfebb8
--- /dev/null
+++ b/em-format/e-mail-parser-message.c
@@ -0,0 +1,129 @@
+/*
+ * e-mail-parser-message.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include "e-mail-part-utils.h"
+#include <libemail-engine/e-mail-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserMessage {
+	GObject parent;
+} EMailParserMessage;
+
+typedef struct _EMailParserMessageClass {
+	GObjectClass parent_class;
+} EMailParserMessageClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMessage,
+	e_mail_parser_message,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar *parser_mime_types[] = { "application/vnd.evolution.message", NULL };
+
+static GSList *
+empe_message_parse (EMailParserExtension *extension,
+                    EMailParser *parser,
+                    CamelMimePart *part,
+                    GString *part_id,
+                    GCancellable *cancellable)
+{
+	GSList *parts;
+	CamelContentType *ct;
+	gchar *mime_type;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	/* Headers */
+	parts = g_slist_concat (NULL, e_mail_parser_parse_part_as (
+					parser, part, part_id,
+					"application/vnd.evolution.headers",
+					cancellable));
+
+	/* Attachment Bar */
+	parts = g_slist_concat (parts, e_mail_parser_parse_part_as (
+					parser, part, part_id,
+					"application/vnd.evolution.widget.attachment-bar",
+					cancellable));
+
+	ct = camel_mime_part_get_content_type (part);
+	mime_type = camel_content_type_simple (ct);
+
+	/* Actual message body */
+	parts = g_slist_concat (parts, e_mail_parser_parse_part_as (
+					parser, part, part_id, mime_type,
+					cancellable));
+
+	g_free (mime_type);
+
+	return parts;
+}
+
+static const gchar **
+empe_message_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_message_class_init (EMailParserMessageClass *klass)
+{
+	e_mail_parser_message_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_message_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_message_mime_types;
+}
+
+static void
+e_mail_parser_message_init (EMailParserMessage *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-multipart-alternative.c b/em-format/e-mail-parser-multipart-alternative.c
new file mode 100644
index 0000000..c8bbfdc
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-alternative.c
@@ -0,0 +1,191 @@
+/*
+ * e-mail-parser-multipart-alternative.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserMultipartAlternative {
+	GObject parent;
+} EMailParserMultipartAlternative;
+
+typedef struct _EMailParserMultipartAlternativeClass {
+	GObjectClass parent_class;
+} EMailParserMultipartAlternativeClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMultipartAlternative,
+	e_mail_parser_multipart_alternative,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "multipart/alternative", NULL };
+
+static gboolean
+related_display_part_is_attachment (CamelMimePart *part)
+{
+	CamelMimePart *display_part;
+
+	display_part = e_mail_part_get_related_display_part (part, NULL);
+	return display_part && e_mail_part_is_attachment (display_part);
+}
+
+static GSList *
+empe_mp_alternative_parse (EMailParserExtension *extension,
+                           EMailParser *parser,
+                           CamelMimePart *part,
+                           GString *part_id,
+                           GCancellable *cancellable)
+{
+	CamelMultipart *mp;
+	gint i, nparts, bestid = 0;
+	CamelMimePart *best = NULL;
+	GSList *parts;
+	EMailExtensionRegistry *reg;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	reg = e_mail_parser_get_extension_registry (parser);
+
+	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+	if (!CAMEL_IS_MULTIPART (mp)) {
+		return e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.source",
+				cancellable);
+	}
+
+	/* as per rfc, find the last part we know how to display */
+	nparts = camel_multipart_get_number (mp);
+	for (i = 0; i < nparts; i++) {
+		CamelMimePart *mpart;
+		CamelDataWrapper *data_wrapper;
+		CamelContentType *type;
+		CamelStream *null_stream;
+		gchar *mime_type;
+		gsize content_size;
+
+		if (g_cancellable_is_cancelled (cancellable))
+			return NULL;
+
+		/* is it correct to use the passed in *part here? */
+		mpart = camel_multipart_get_part (mp, i);
+
+		if (mpart == NULL)
+			continue;
+
+		/* This may block even though the stream does not.
+		 * XXX Pretty inefficient way to test if the MIME part
+		 *     is empty.  Surely there's a quicker way? */
+		null_stream = camel_stream_null_new ();
+		data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (mpart));
+		camel_data_wrapper_decode_to_stream_sync (
+			data_wrapper, null_stream, cancellable, NULL);
+		content_size = CAMEL_STREAM_NULL (null_stream)->written;
+		g_object_unref (null_stream);
+
+		if (content_size == 0)
+			continue;
+
+		type = camel_mime_part_get_content_type (mpart);
+		mime_type = camel_content_type_simple (type);
+
+		camel_strdown (mime_type);
+
+		if (!e_mail_part_is_attachment (mpart) &&
+			 ((camel_content_type_is (type, "multipart", "related") == 0) ||
+			  !related_display_part_is_attachment (mpart)) &&
+		    (e_mail_extension_registry_get_for_mime_type (reg, mime_type) ||
+			((best == NULL) &&
+			 (e_mail_extension_registry_get_fallback (reg, mime_type)))))
+		{
+			best = mpart;
+			bestid = i;
+		}
+
+		g_free (mime_type);
+	}
+
+	if (best) {
+		gint len = part_id->len;
+
+		g_string_append_printf(part_id, ".alternative.%d", bestid);
+
+		parts = e_mail_parser_parse_part (
+			parser, best, part_id, cancellable);
+
+		g_string_truncate (part_id, len);
+	} else {
+		parts = e_mail_parser_parse_part_as (
+			parser, part, part_id, "multipart/mixed", cancellable);
+	}
+
+	return parts;
+}
+
+static const gchar **
+empe_mp_alternative_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_multipart_alternative_class_init (EMailParserMultipartAlternativeClass *klass)
+{
+	e_mail_parser_multipart_alternative_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_mp_alternative_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_mp_alternative_mime_types;
+}
+
+static void
+e_mail_parser_multipart_alternative_init (EMailParserMultipartAlternative *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-multipart-appledouble.c b/em-format/e-mail-parser-multipart-appledouble.c
new file mode 100644
index 0000000..5591b10
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-appledouble.c
@@ -0,0 +1,130 @@
+/*
+ * e-mail-parser-multipart-appledouble.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+
+#include <camel/camel.h>
+
+typedef struct _EMailParserMultipartAppleDouble {
+	GObject parent;
+} EMailParserMultipartAppleDouble;
+
+typedef struct _EMailParserMultipartAppleDoubleClass {
+	GObjectClass parent_class;
+} EMailParserMultipartAppleDoubleClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMultipartAppleDouble,
+	e_mail_parser_multipart_apple_double,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "multipart/appledouble", NULL };
+
+static GSList *
+empe_mp_appledouble_parse (EMailParserExtension *extension,
+                           EMailParser *parser,
+                           CamelMimePart *part,
+                           GString *part_id,
+                           GCancellable *cancellable)
+{
+	CamelMultipart *mp;
+	GSList *parts;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+	if (!CAMEL_IS_MULTIPART (mp)) {
+		parts = e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.source",
+				cancellable);
+	} else {
+		CamelMimePart *mime_part;
+		mime_part = camel_multipart_get_part (mp, 1);
+
+		if (mime_part) {
+			gint len;
+			/* try the data fork for something useful, doubtful but who knows */
+			len = part_id->len;
+			g_string_append_printf(part_id, ".appledouble.1");
+
+			parts = e_mail_parser_parse_part (
+					parser, mime_part, part_id, cancellable);
+
+			g_string_truncate (part_id, len);
+
+		} else {
+
+			parts = e_mail_parser_parse_part_as (
+					parser, part, part_id,
+					"application/vnd.evolution.source",
+					cancellable);
+		}
+	}
+
+	return parts;
+}
+
+static const gchar **
+empe_mp_appledouble_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_multipart_apple_double_class_init (EMailParserMultipartAppleDoubleClass *klass)
+{
+	e_mail_parser_multipart_apple_double_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_mp_appledouble_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_mp_appledouble_mime_types;
+}
+
+static void
+e_mail_parser_multipart_apple_double_init (EMailParserMultipartAppleDouble *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-multipart-digest.c b/em-format/e-mail-parser-multipart-digest.c
new file mode 100644
index 0000000..5b96d1f
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-digest.c
@@ -0,0 +1,175 @@
+/*
+ * e-mail-parser-multipart-digest.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserMultipartDigest {
+	GObject parent;
+} EMailParserMultipartDigest;
+
+typedef struct _EMailParserMultipartDigestClass {
+	GObjectClass parent_class;
+} EMailParserMultipartDigestClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMultipartDigest,
+	e_mail_parser_multipart_digest,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "multipart/digest",
+					    NULL };
+
+static GSList *
+empe_mp_digest_parse (EMailParserExtension *extension,
+                      EMailParser *parser,
+                      CamelMimePart *part,
+                      GString *part_id,
+                      GCancellable *cancellable)
+{
+	CamelMultipart *mp;
+	gint i, nparts, len;
+	GSList *parts;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+	if (!CAMEL_IS_MULTIPART (mp)) {
+		return e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.source", cancellable);
+	}
+
+	len = part_id->len;
+	nparts = camel_multipart_get_number (mp);
+	parts = NULL;
+	for (i = 0; i < nparts; i++) {
+		CamelMimePart *subpart;
+		CamelContentType *ct;
+		gchar *cts;
+
+		subpart = camel_multipart_get_part (mp, i);
+
+		if (!subpart)
+			continue;
+
+		g_string_append_printf(part_id, ".digest.%d", i);
+
+		ct = camel_mime_part_get_content_type (subpart);
+
+		/* According to RFC this shouldn't happen, but who knows... */
+		if (ct && !camel_content_type_is (ct, "message", "rfc822")) {
+			cts = camel_content_type_simple (ct);
+
+			parts = g_slist_concat (parts,
+					e_mail_parser_parse_part_as (
+						parser, subpart, part_id,
+						cts, cancellable));
+
+			g_free (cts);
+		} else {
+			GSList *new_parts;
+
+			new_parts = e_mail_parser_parse_part_as (
+					parser, subpart, part_id,
+					"message/rfc822", cancellable);
+
+			/* Force the message to be collapsable */
+			if (new_parts && new_parts->data &&
+			    !E_MAIL_PART (new_parts->data)->is_attachment) {
+				new_parts = e_mail_parser_wrap_as_attachment (
+					parser, subpart, new_parts, part_id,
+					cancellable);
+			}
+
+			/* Force the message to be expanded */
+			if (new_parts) {
+				EMailPart *p = new_parts->data;
+				if (p) {
+					p->force_inline = TRUE;
+				}
+			}
+
+			parts = g_slist_concat (parts, new_parts);
+		}
+
+		g_string_truncate (part_id, len);
+	}
+
+	return parts;
+}
+
+static guint32
+empe_mp_digest_get_flags (EMailParserExtension *extension)
+{
+	return E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE;
+}
+
+static const gchar **
+empe_mp_digest_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_multipart_digest_class_init (EMailParserMultipartDigestClass *klass)
+{
+	e_mail_parser_multipart_digest_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_mp_digest_parse;
+	iface->get_flags = empe_mp_digest_get_flags;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_mp_digest_mime_types;
+}
+
+static void
+e_mail_parser_multipart_digest_init (EMailParserMultipartDigest *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-multipart-encrypted.c b/em-format/e-mail-parser-multipart-encrypted.c
new file mode 100644
index 0000000..f03588a
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-encrypted.c
@@ -0,0 +1,220 @@
+/*
+ * e-mail-parser-multipart-encrypted.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+typedef struct _EMailParserMultipartEncrypted {
+	GObject parent;
+} EMailParserMultipartEncrypted;
+
+typedef struct _EMailParserMultipartEncryptedClass {
+	GObjectClass parent_class;
+} EMailParserMultipartEncryptedClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMultipartEncrypted,
+	e_mail_parser_multipart_encrypted,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init))
+
+static const gchar* parser_mime_types[] = { "multipart/encrypted", NULL };
+
+static GSList *
+empe_mp_encrypted_parse (EMailParserExtension *extension,
+                         EMailParser *parser,
+                         CamelMimePart *part,
+                         GString *part_id,
+                         GCancellable *cancellable)
+{
+	CamelCipherContext *context;
+	const gchar *protocol;
+	CamelMimePart *opart;
+	CamelCipherValidity *valid;
+	CamelMultipartEncrypted *mpe;
+	GError *local_error = NULL;
+	GSList *parts;
+	gint len;
+	GSList *iter;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	mpe = (CamelMultipartEncrypted *) camel_medium_get_content ((CamelMedium *) part);
+	if (!CAMEL_IS_MULTIPART_ENCRYPTED (mpe)) {
+		parts = e_mail_parser_error (
+				parser, cancellable,
+				_("Could not parse MIME message. "
+				  "Displaying as source."));
+		parts = g_slist_concat (
+				parts,
+				e_mail_parser_parse_part_as (
+					parser, part, part_id,
+				 	"application/vnd.evolution/source",
+					cancellable));
+
+		return parts;
+	}
+
+	/* Currently we only handle RFC2015-style PGP encryption. */
+	protocol = camel_content_type_param (
+		((CamelDataWrapper *)mpe)->mime_type, "protocol");
+	if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) {
+		parts = e_mail_parser_error (
+				parser, cancellable,
+			       _("Unsupported encryption type for multipart/encrypted"));
+
+		parts = g_slist_concat (
+				parts,
+				e_mail_parser_parse_part_as (
+					parser, part, part_id,
+				   	"multipart/mixed", cancellable));
+		return parts;
+	}
+
+	context = camel_gpg_context_new (e_mail_parser_get_session (parser));
+
+	opart = camel_mime_part_new ();
+	valid = camel_cipher_context_decrypt_sync (
+			context, part, opart, cancellable, &local_error);
+
+	e_mail_part_preserve_charset_in_content_type (part, opart);
+	if (valid == NULL) {
+		parts = e_mail_parser_error (
+				parser, cancellable,
+				_("Could not parse PGP/MIME message: %s"),
+				local_error->message ?
+					local_error->message :
+					_("Unknown error"));
+
+		g_clear_error (&local_error);
+
+		parts = g_slist_concat (parts,
+				e_mail_parser_parse_part_as (
+					parser, part, part_id,
+				 	"multipart/mixed", cancellable));
+
+		g_object_unref (opart);
+		g_object_unref (context);
+
+		return parts;
+	}
+
+	len = part_id->len;
+	g_string_append (part_id, ".encrypted");
+
+	parts = e_mail_parser_parse_part (
+			parser, opart, part_id, cancellable);
+
+	g_string_truncate (part_id, len);
+
+	/* Update validity of all encrypted sub-parts */
+	for (iter = parts; iter; iter = iter->next) {
+		EMailPart *mail_part;
+
+		mail_part = iter->data;
+		if (!mail_part)
+			continue;
+
+		e_mail_part_update_validity (mail_part, valid,
+			E_MAIL_PART_VALIDITY_ENCRYPTED |
+			E_MAIL_PART_VALIDITY_PGP);
+	}
+
+	/* Add a widget with details about the encryption, but only when
+		* the decrypted part isn't itself secured, in that case it has created
+		* the button itself */
+	if (!e_mail_part_is_secured (opart)) {
+		GSList *button;
+		EMailPart *mail_part;
+		g_string_append (part_id, ".encrypted.button");
+
+		button = e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.widget.secure-button",
+				cancellable);
+		if (button && button->data) {
+			mail_part = button->data;
+
+			e_mail_part_update_validity (mail_part, valid,
+				E_MAIL_PART_VALIDITY_ENCRYPTED |
+				E_MAIL_PART_VALIDITY_PGP);
+		}
+
+		parts = g_slist_concat (parts, button);
+
+		g_string_truncate (part_id, len);
+	}
+
+	camel_cipher_validity_free (valid);
+
+	/* TODO: Make sure when we finalize this part, it is zero'd out */
+	g_object_unref (opart);
+	g_object_unref (context);
+
+	return parts;
+}
+
+static const gchar **
+empe_mp_encrypted_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_multipart_encrypted_class_init (EMailParserMultipartEncryptedClass *klass)
+{
+	e_mail_parser_multipart_encrypted_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_mp_encrypted_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_mp_encrypted_mime_types;
+}
+
+static void
+e_mail_parser_multipart_encrypted_init (EMailParserMultipartEncrypted *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-multipart-mixed.c b/em-format/e-mail-parser-multipart-mixed.c
new file mode 100644
index 0000000..0da450f
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-mixed.c
@@ -0,0 +1,158 @@
+/*
+ * e-mail-parser-multipart-mixed.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <e-util/e-util.h>
+#include <em-format/e-mail-part-utils.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserMultipartMixed {
+	GObject parent;
+} EMailParserMultipartMixed;
+
+typedef struct _EMailParserMultipartMixedClass {
+	GObjectClass parent_class;
+} EMailParserMultipartMixedClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMultipartMixed,
+	e_mail_parser_multipart_mixed,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "multipart/mixed",
+					    "multipart/report",
+					    "multipart/*",
+					    NULL };
+
+static GSList *
+empe_mp_mixed_parse (EMailParserExtension *extension,
+                     EMailParser *parser,
+                     CamelMimePart *part,
+                     GString *part_id,
+                     GCancellable *cancellable)
+{
+	CamelMultipart *mp;
+	gint i, nparts, len;
+	GSList *parts;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+	if (!CAMEL_IS_MULTIPART (mp)) {
+		parts = e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.source", cancellable);
+		return parts;
+	}
+
+	len = part_id->len;
+	parts = NULL;
+	nparts = camel_multipart_get_number (mp);
+	for (i = 0; i < nparts; i++) {
+		CamelMimePart *subpart;
+		CamelContentType *ct;
+		GSList *new_parts;
+
+		subpart = camel_multipart_get_part (mp, i);
+
+		g_string_append_printf(part_id, ".mixed.%d", i);
+
+		new_parts = e_mail_parser_parse_part (
+				parser, subpart, part_id, cancellable);
+
+		/* Force messages to be expandable */
+		ct = camel_mime_part_get_content_type (subpart);
+		if (!new_parts ||
+		    (camel_content_type_is (ct, "message", "rfc822") &&
+		     new_parts && new_parts->data &&
+		     !E_MAIL_PART (new_parts->data)->is_attachment)) {
+
+			parts = g_slist_concat (parts,
+					e_mail_parser_wrap_as_attachment (
+						parser, subpart, new_parts,
+						part_id, cancellable));
+			if (parts && parts->data)
+				E_MAIL_PART (parts->data)->force_inline = TRUE;
+		} else {
+			parts = g_slist_concat (parts, new_parts);
+		}
+
+		g_string_truncate (part_id, len);
+	}
+
+	return parts;
+}
+
+static guint32
+empe_mp_mixed_get_flags (EMailParserExtension *extension)
+{
+	return E_MAIL_PARSER_EXTENSION_COMPOUND_TYPE;
+}
+
+static const gchar **
+empe_mp_mixed_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_multipart_mixed_class_init (EMailParserMultipartMixedClass *klass)
+{
+	e_mail_parser_multipart_mixed_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_mp_mixed_parse;
+	iface->get_flags = empe_mp_mixed_get_flags;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_mp_mixed_mime_types;
+}
+
+static void
+e_mail_parser_multipart_mixed_init (EMailParserMultipartMixed *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-multipart-related.c b/em-format/e-mail-parser-multipart-related.c
new file mode 100644
index 0000000..ff76212
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-related.c
@@ -0,0 +1,162 @@
+/*
+ * e-mail-parser-multipart-related.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserMultipartRelated {
+	GObject parent;
+} EMailParserMultipartRelated;
+
+typedef struct _EMailParserMultipartRelatedClass {
+	GObjectClass parent_class;
+} EMailParserMultipartRelatedClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMultipartRelated,
+	e_mail_parser_multipart_related,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "multipart/related",
+					    NULL };
+
+static GSList *
+empe_mp_related_parse (EMailParserExtension *extension,
+                       EMailParser *parser,
+                       CamelMimePart *part,
+                       GString *part_id,
+                       GCancellable *cancellable)
+{
+	CamelMultipart *mp;
+	CamelMimePart *body_part, *display_part = NULL;
+	gint i, nparts, partidlen, displayid = 0;
+	GSList *parts;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+	if (!CAMEL_IS_MULTIPART (mp)) {
+		return e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.source", cancellable);
+	}
+
+	display_part = e_mail_part_get_related_display_part (part, &displayid);
+
+	if (display_part == NULL) {
+		return e_mail_parser_parse_part_as (
+				parser, part, part_id, "multipart/mixed",
+				cancellable);
+	}
+
+	/* The to-be-displayed part goes first */
+	partidlen = part_id->len;
+	g_string_append_printf(part_id, ".related.%d", displayid);
+
+	parts = e_mail_parser_parse_part (
+			parser, display_part, part_id, cancellable);
+
+	g_string_truncate (part_id, partidlen);
+
+	/* Process the related parts */
+	nparts = camel_multipart_get_number (mp);
+	for (i = 0; i < nparts; i++) {
+		GSList *list, *iter;
+		body_part = camel_multipart_get_part (mp, i);
+		list = NULL;
+
+		if (body_part == display_part)
+			continue;
+
+		g_string_append_printf(part_id, ".related.%d", i);
+
+		list = e_mail_parser_parse_part (
+				parser, body_part, part_id, cancellable);
+
+		g_string_truncate (part_id, partidlen);
+
+		for (iter = list; iter; iter = iter->next) {
+			EMailPart *mail_part;
+
+			mail_part = iter->data;
+			if (!mail_part)
+				continue;
+
+			/* Don't render the part on it's own! */
+			mail_part->is_hidden = TRUE;
+		}
+
+		parts = g_slist_concat (parts, list);
+	}
+
+	return parts;
+}
+
+static const gchar **
+empe_mp_related_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_multipart_related_class_init (EMailParserMultipartRelatedClass *klass)
+{
+	e_mail_parser_multipart_related_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_mp_related_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_mp_related_mime_types;
+}
+
+static void
+e_mail_parser_multipart_related_init (EMailParserMultipartRelated *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-multipart-signed.c b/em-format/e-mail-parser-multipart-signed.c
new file mode 100644
index 0000000..37bedc9
--- /dev/null
+++ b/em-format/e-mail-parser-multipart-signed.c
@@ -0,0 +1,252 @@
+/*
+ * e-mail-parser-multipart-signed.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+typedef struct _EMailParserMultipartSigned {
+	GObject parent;
+} EMailParserMultipartSigned;
+
+typedef struct _EMailParserMultipartSignedClass {
+	GObjectClass parent_class;
+} EMailParserMultipartSignedClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserMultipartSigned,
+	e_mail_parser_multipart_signed,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar* parser_mime_types[] = { "multipart/signed",
+					    "application/pgp-signature",
+					    NULL };
+
+static GSList *
+empe_mp_signed_parse (EMailParserExtension *extension,
+                      EMailParser *parser,
+                      CamelMimePart *part,
+                      GString *part_id,
+                      GCancellable *cancellable)
+{
+	CamelMimePart *cpart;
+	CamelMultipartSigned *mps;
+	CamelCipherContext *cipher = NULL;
+	CamelSession *session;
+	guint32 validity_type;
+	GSList *parts;
+	CamelCipherValidity *valid;
+	GError *local_error = NULL;
+	gint i, nparts, len;
+	gboolean secured;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	/* If the part is application/pgp-signature sub-part then skip it. */
+	if (!CAMEL_IS_MULTIPART (part)) {
+		CamelContentType *ct;
+		ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (part));
+		if (camel_content_type_is (ct, "application", "pgp-signature")) {
+			return g_slist_alloc ();
+		}
+	}
+
+	mps = (CamelMultipartSigned *) camel_medium_get_content ((CamelMedium *) part);
+	if (!CAMEL_IS_MULTIPART_SIGNED (mps)
+	    || (cpart = camel_multipart_get_part ((CamelMultipart *) mps,
+		CAMEL_MULTIPART_SIGNED_CONTENT)) == NULL) {
+		parts = e_mail_parser_error (
+				parser, cancellable,
+				_("Could not parse MIME message. "
+				"Displaying as source."));
+
+		parts = g_slist_concat (parts,
+				e_mail_parser_parse_part_as (
+					parser, part, part_id,
+					"application/vnd.evolution.source",
+					cancellable));
+		return parts;
+	}
+
+	session = e_mail_parser_get_session (parser);
+	/* FIXME: Should be done via a plugin interface */
+	/* FIXME: duplicated in em-format-html-display.c */
+	if (mps->protocol) {
+#ifdef ENABLE_SMIME
+		if (g_ascii_strcasecmp("application/x-pkcs7-signature", mps->protocol) == 0
+		    || g_ascii_strcasecmp("application/pkcs7-signature", mps->protocol) == 0) {
+			cipher = camel_smime_context_new (session);
+			validity_type = E_MAIL_PART_VALIDITY_SMIME;
+		} else {
+#endif
+			if (g_ascii_strcasecmp("application/pgp-signature", mps->protocol) == 0) {
+				cipher = camel_gpg_context_new (session);
+				validity_type = E_MAIL_PART_VALIDITY_PGP;
+			}
+#ifdef ENABLE_SMIME
+		}
+#endif
+	}
+
+	if (cipher == NULL) {
+		parts = e_mail_parser_error (
+				parser, cancellable,
+				_("Unsupported signature format"));
+
+		parts = g_slist_concat (parts,
+				e_mail_parser_parse_part_as (
+					parser, part, part_id,
+				 	"multipart/mixed", cancellable));
+
+		return parts;
+	}
+
+	valid = camel_cipher_context_verify_sync (
+		cipher, part, cancellable, &local_error);
+	if (valid == NULL) {
+		parts = e_mail_parser_error (
+				parser, cancellable,
+				_("Error verifying signature: %s"),
+				local_error->message ?
+					local_error->message :
+					_("Unknown error"));
+
+		g_clear_error (&local_error);
+
+		parts = g_slist_concat (parts,
+				e_mail_parser_parse_part_as (
+					parser, part, part_id,
+					"multipart/mixed", cancellable));
+
+		g_object_unref (cipher);
+		return parts;
+	}
+
+	nparts = camel_multipart_get_number (CAMEL_MULTIPART (mps));
+	secured = FALSE;
+	len = part_id->len;
+	parts = NULL;
+	for (i = 0; i < nparts; i++) {
+		CamelMimePart *subpart;
+		GSList *mail_parts, *iter;
+		subpart = camel_multipart_get_part (CAMEL_MULTIPART (mps), i);
+
+		g_string_append_printf(part_id, ".signed.%d", i);
+
+		mail_parts = e_mail_parser_parse_part (
+				parser, subpart, part_id, cancellable);
+
+		g_string_truncate (part_id, len);
+
+		if (!secured)
+			secured = e_mail_part_is_secured (subpart);
+
+		for (iter = mail_parts; iter; iter = iter->next) {
+			EMailPart *mail_part;
+
+			mail_part = iter->data;
+			if (!mail_part)
+				continue;
+
+			e_mail_part_update_validity (mail_part, valid,
+				validity_type | E_MAIL_PART_VALIDITY_SIGNED);
+		}
+
+		parts = g_slist_concat (parts, mail_parts);
+	}
+
+	/* Add a widget with details about the encryption, but only when
+		* the encrypted isn't itself secured, in that case it has created
+		* the button itself */
+	if (!secured) {
+		GSList *button;
+		EMailPart *mail_part;
+		g_string_append (part_id, ".signed.button");
+
+		button = e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.widget.secure-button",
+				cancellable);
+		if (button && button->data) {
+			mail_part = button->data;
+
+			e_mail_part_update_validity (mail_part, valid,
+				validity_type | E_MAIL_PART_VALIDITY_SIGNED);
+		}
+
+		parts = g_slist_concat (parts, button);
+
+		g_string_truncate (part_id, len);
+	}
+
+	camel_cipher_validity_free (valid);
+
+	g_object_unref (cipher);
+
+	return parts;
+}
+
+static const gchar **
+empe_mp_signed_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_multipart_signed_class_init (EMailParserMultipartSignedClass *klass)
+{
+	e_mail_parser_multipart_signed_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_mp_signed_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_mp_signed_mime_types;
+}
+
+static void
+e_mail_parser_multipart_signed_init (EMailParserMultipartSigned *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-secure-button.c b/em-format/e-mail-parser-secure-button.c
new file mode 100644
index 0000000..6c8a0e6
--- /dev/null
+++ b/em-format/e-mail-parser-secure-button.c
@@ -0,0 +1,104 @@
+/*
+ * e-mail-parser-secure-button.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "e-mail-format-extensions.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <e-util/e-util.h>
+
+#include <camel/camel.h>
+
+typedef struct _EMailParserSecureButton {
+	GObject parent;
+} EMailParserSecureButton;
+
+typedef struct _EMailParserSecureButtonClass {
+	GObjectClass parent_class;
+} EMailParserSecureButtonClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserSecureButton,
+	e_mail_parser_secure_button,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init))
+
+static const gchar *parser_mime_types[] = { "application/vnd.evolution.widget.secure-button", NULL };
+
+static GSList *
+empe_secure_button_parse (EMailParserExtension *extension,
+                          EMailParser *parser,
+                          CamelMimePart *part,
+                          GString *part_id,
+                          GCancellable *cancellable)
+{
+	EMailPart *mail_part;
+	gint len;
+
+	len = part_id->len;
+	g_string_append (part_id, ".secure_button");
+	mail_part = e_mail_part_new (part, part_id->str);
+	mail_part->mime_type = g_strdup ("application/vnd.evolution.widget.secure-button");
+	g_string_truncate (part_id, len);
+
+	return g_slist_append (NULL, mail_part);
+}
+
+static const gchar **
+empe_secure_button_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_secure_button_class_init (EMailParserSecureButtonClass *klass)
+{
+	e_mail_parser_secure_button_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_secure_button_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_secure_button_mime_types;
+}
+
+static void
+e_mail_parser_secure_button_init (EMailParserSecureButton *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-source.c b/em-format/e-mail-parser-source.c
new file mode 100644
index 0000000..ae1a9a3
--- /dev/null
+++ b/em-format/e-mail-parser-source.c
@@ -0,0 +1,108 @@
+/*
+ * e-mail-parser-source.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+typedef struct _EMailParserSource {
+	GObject parent;
+} EMailParserSource;
+
+typedef struct _EMailParserSourceClass {
+	GObjectClass parent_class;
+} EMailParserSourceClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserSource,
+	e_mail_parser_source,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar *parser_mime_types[] = { "application/vnd.evolution.source", NULL };
+
+static GSList *
+empe_source_parse (EMailParserExtension *extension,
+                   EMailParser *parser,
+                   CamelMimePart *part,
+                   GString *part_id,
+                   GCancellable *cancellable)
+{
+	EMailPart *mail_part;
+	gint len;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	len = part_id->len;
+	g_string_append (part_id, ".source");
+
+	mail_part = e_mail_part_new (part, part_id->str);
+	mail_part->mime_type = g_strdup ("application/vnd.evolution.source");
+	g_string_truncate (part_id, len);
+
+	return g_slist_append (NULL, mail_part);
+}
+
+static const gchar **
+empe_source_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_source_class_init (EMailParserSourceClass *klass)
+{
+	e_mail_parser_source_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_source_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_source_mime_types;
+}
+
+static void
+e_mail_parser_source_init (EMailParserSource *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-text-enriched.c b/em-format/e-mail-parser-text-enriched.c
new file mode 100644
index 0000000..fad71f8
--- /dev/null
+++ b/em-format/e-mail-parser-text-enriched.c
@@ -0,0 +1,128 @@
+/*
+ * e-mail-parser-text-enriched.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+typedef struct _EMailParserTextEnriched {
+	GObject parent;
+} EMailParserTextEnriched;
+
+typedef struct _EMailParserTextEnrichedClass {
+	GObjectClass parent_class;
+} EMailParserTextEnrichedClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserTextEnriched,
+	e_mail_parser_text_enriched,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar *parser_mime_types[] = { "text/richtext",
+					    "text/enriched",
+					    NULL };
+
+static GSList *
+empe_text_enriched_parse (EMailParserExtension *extension,
+                          EMailParser *parser,
+                          CamelMimePart *part,
+                          GString *part_id,
+                          GCancellable *cancellable)
+{
+	EMailPart *mail_part;
+	const gchar *tmp;
+	gint len;
+	CamelContentType *ct;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	len = part_id->len;
+	g_string_append (part_id, ".text_enriched");
+
+	ct = camel_mime_part_get_content_type (part);
+
+	mail_part = e_mail_part_new (part, part_id->str);
+	mail_part->mime_type = ct ? camel_content_type_simple (ct) : g_strdup ("text/enriched");
+	tmp = camel_mime_part_get_content_id (part);
+	if (!tmp) {
+		mail_part->cid = NULL;
+	} else {
+		mail_part->cid = g_strdup_printf ("cid:%s", tmp);
+	}
+
+	g_string_truncate (part_id, len);
+
+	if (e_mail_part_is_attachment (part)) {
+		return e_mail_parser_wrap_as_attachment (
+				parser, part, g_slist_append (NULL, mail_part),
+				part_id, cancellable);
+	}
+
+	return g_slist_append (NULL, mail_part);
+}
+
+static const gchar **
+empe_text_enriched_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_text_enriched_class_init (EMailParserTextEnrichedClass *klass)
+{
+	e_mail_parser_text_enriched_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_text_enriched_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_text_enriched_mime_types;
+}
+
+static void
+e_mail_parser_text_enriched_init (EMailParserTextEnriched *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-text-html.c b/em-format/e-mail-parser-text-html.c
new file mode 100644
index 0000000..05c7bcd
--- /dev/null
+++ b/em-format/e-mail-parser-text-html.c
@@ -0,0 +1,138 @@
+/*
+ * e-mail-parser-text-html.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
+#include <string.h>
+
+typedef struct _EMailParserTextHTML {
+	GObject parent;
+} EMailParserTextHTML;
+
+typedef struct _EMailParserTextHTMLClass {
+	GObjectClass parent_class;
+} EMailParserTextHTMLClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserTextHTML,
+	e_mail_parser_text_html,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar *parser_mime_types[] = { "text/html", NULL };
+
+static GSList *
+empe_text_html_parse (EMailParserExtension *extension,
+                      EMailParser *parser,
+                      CamelMimePart *part,
+                      GString *part_id,
+                      GCancellable *cancellable)
+{
+	EMailPart *empart;
+	const gchar *location;
+	gchar *cid = NULL;
+	const gchar *base;
+	gint len;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	cid = NULL;
+	base = camel_medium_get_header (CAMEL_MEDIUM (part), "content-base");
+	location = camel_mime_part_get_content_location (part);
+	if (location != NULL) {
+		if (strchr (location, ':') == NULL && base != NULL) {
+			CamelURL *uri;
+			CamelURL *base_url = camel_url_new (base, NULL);
+
+			uri = camel_url_new_with_base (base_url, location);
+			cid = camel_url_to_string (uri, 0);
+			camel_url_free (uri);
+			camel_url_free (base_url);
+		} else {
+			cid = g_strdup (location);
+		}
+	}
+
+	len = part_id->len;
+	g_string_append (part_id, ".text_html");
+
+	empart = e_mail_part_new (part, part_id->str);
+	empart->mime_type = g_strdup ("text/html");
+	empart->cid = cid;
+	g_string_truncate (part_id, len);
+
+	if (e_mail_part_is_attachment (part)) {
+		return e_mail_parser_wrap_as_attachment (
+				parser, part, g_slist_append (NULL, empart),
+				part_id, cancellable);
+	}
+
+	return g_slist_append (NULL, empart);
+}
+
+static const gchar **
+empe_text_html_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_text_html_class_init (EMailParserTextHTMLClass *klass)
+{
+	e_mail_parser_text_html_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_text_html_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_text_html_mime_types;
+}
+
+static void
+e_mail_parser_text_html_init (EMailParserTextHTML *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser-text-plain.c b/em-format/e-mail-parser-text-plain.c
new file mode 100644
index 0000000..9990304
--- /dev/null
+++ b/em-format/e-mail-parser-text-plain.c
@@ -0,0 +1,253 @@
+/*
+ * e-mail-parser-text-plain.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-mail-format-extensions.h"
+
+#include <em-format/e-mail-parser-extension.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-inline-filter.h>
+#include <em-format/e-mail-part-utils.h>
+#include <e-util/e-util.h>
+
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+#include <ctype.h>
+
+typedef struct _EMailParserTextPlain {
+	GObject parent;
+} EMailParserTextPlain;
+
+typedef struct _EMailParserTextPlainClass {
+	GObjectClass parent_class;
+} EMailParserTextPlainClass;
+
+static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
+static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+	EMailParserTextPlain,
+	e_mail_parser_text_plain,
+	G_TYPE_OBJECT,
+	0,
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_EXTENSION,
+		e_mail_parser_mail_extension_interface_init)
+	G_IMPLEMENT_INTERFACE (
+		E_TYPE_MAIL_PARSER_EXTENSION,
+		e_mail_parser_parser_extension_interface_init));
+
+static const gchar *parser_mime_types[] = { "text/plain", "text/*", NULL };
+
+static gboolean
+part_is_empty (CamelMimePart *part)
+{
+	CamelDataWrapper *dw;
+	GByteArray *ba;
+	guint i;
+
+	dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+	ba = camel_data_wrapper_get_byte_array (dw);
+
+	if (!ba)
+		return TRUE;
+
+	for (i = 0; i < ba->len; i++) {
+
+		/* Checks for \n, \t, \f, \r, \v and space */
+		if (!isspace (ba->data[i]))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+static GSList *
+process_part (EMailParser *parser,
+              GString *part_id,
+              gint part_number,
+              CamelMimePart *part,
+              gboolean is_attachment,
+              GCancellable *cancellable)
+{
+	CamelContentType *type;
+	EMailPart *empart;
+	gint s_len = part_id->len;
+	GSList *parts;
+
+	if (part_is_empty (part)) {
+		return g_slist_alloc ();
+	}
+
+	type = camel_mime_part_get_content_type (part);
+	if (camel_content_type_is (type, "text", "*") &&
+		(!camel_content_type_is (type, "text", "calendar"))) {
+
+		g_string_append_printf (part_id, ".plain_text.%d", part_number);
+
+		empart = e_mail_part_new (part, part_id->str);
+		empart->mime_type = camel_content_type_simple (type);
+
+		g_string_truncate (part_id, s_len);
+
+		if (is_attachment) {
+
+			return e_mail_parser_wrap_as_attachment (
+					parser, part,
+					g_slist_append (NULL, empart),
+					part_id, cancellable);
+
+		}
+
+		return g_slist_append (NULL, empart);
+	}
+
+	g_string_append_printf (part_id, ".inline.%d", part_number);
+
+	parts = e_mail_parser_parse_part (
+			parser, CAMEL_MIME_PART (part),
+			part_id, cancellable);
+
+	g_string_truncate (part_id, s_len);
+
+	return parts;
+}
+
+static GSList *
+empe_text_plain_parse (EMailParserExtension *extension,
+                       EMailParser *parser,
+                       CamelMimePart *part,
+                       GString *part_id,
+                       GCancellable *cancellable)
+{
+	GSList *parts;
+	CamelStream *filtered_stream, *null;
+	CamelMultipart *mp;
+	CamelDataWrapper *dw;
+	CamelContentType *type;
+	gint i, count;
+	EMailInlineFilter *inline_filter;
+	gboolean charset_added = FALSE;
+	const gchar *snoop_type = NULL;
+	gboolean is_attachment;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	dw = camel_medium_get_content ((CamelMedium *) part);
+	if (!dw)
+		return NULL;
+
+	/* This scans the text part for inline-encoded data, creates
+	 * a multipart of all the parts inside it. */
+
+	/* FIXME: We should discard this multipart if it only contains
+	 * the original text, but it makes this hash lookup more complex */
+	if (!dw->mime_type)
+		snoop_type = e_mail_part_snoop_type (part);
+
+	/* if we had to snoop the part type to get here, then
+	 * use that as the base type, yuck */
+	if (snoop_type == NULL
+		|| (type = camel_content_type_decode (snoop_type)) == NULL) {
+		type = dw->mime_type;
+		camel_content_type_ref (type);
+	}
+
+	if (dw->mime_type && type != dw->mime_type && camel_content_type_param (dw->mime_type, "charset")) {
+		camel_content_type_set_param (type, "charset", camel_content_type_param (dw->mime_type, "charset"));
+		charset_added = TRUE;
+	}
+
+	null = camel_stream_null_new ();
+	filtered_stream = camel_stream_filter_new (null);
+	g_object_unref (null);
+	inline_filter = e_mail_inline_filter_new (camel_mime_part_get_encoding (part), type);
+	camel_stream_filter_add (
+		CAMEL_STREAM_FILTER (filtered_stream),
+		CAMEL_MIME_FILTER (inline_filter));
+	camel_data_wrapper_decode_to_stream_sync (
+		dw, (CamelStream *) filtered_stream, cancellable, NULL);
+	camel_stream_close ((CamelStream *) filtered_stream, cancellable, NULL);
+	g_object_unref (filtered_stream);
+
+	mp = e_mail_inline_filter_get_multipart (inline_filter);
+
+	if (charset_added) {
+		camel_content_type_set_param (type, "charset", NULL);
+	}
+
+	g_object_unref (inline_filter);
+	camel_content_type_unref (type);
+
+	/* We handle our made-up multipart here, so we don't recursively call ourselves */
+	count = camel_multipart_get_number (mp);
+	parts = NULL;
+
+	is_attachment = ((count == 1) && (e_mail_part_is_attachment (part)));
+
+	for (i = 0; i < count; i++) {
+		CamelMimePart *newpart = camel_multipart_get_part (mp, i);
+
+		if (!newpart)
+			continue;
+
+		parts = g_slist_concat (parts,
+				process_part (
+					parser, part_id, i,
+					newpart, is_attachment,
+					cancellable));
+	}
+
+	g_object_unref (mp);
+
+	return parts;
+}
+
+static const gchar **
+empe_text_plain_mime_types (EMailExtension *extension)
+{
+	return parser_mime_types;
+}
+
+static void
+e_mail_parser_text_plain_class_init (EMailParserTextPlainClass *klass)
+{
+	e_mail_parser_text_plain_parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface)
+{
+	iface->parse = empe_text_plain_parse;
+}
+
+static void
+e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface)
+{
+	iface->mime_types = empe_text_plain_mime_types;
+}
+
+static void
+e_mail_parser_text_plain_init (EMailParserTextPlain *parser)
+{
+
+}
diff --git a/em-format/e-mail-parser.c b/em-format/e-mail-parser.c
new file mode 100644
index 0000000..98b31b7
--- /dev/null
+++ b/em-format/e-mail-parser.c
@@ -0,0 +1,693 @@
+/*
+ * e-mail-parser.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-parser.h"
+#include "e-mail-parser-extension.h"
+#include "e-mail-format-extensions.h"
+#include "e-mail-part-attachment.h"
+#include "e-mail-part-utils.h"
+
+#include <camel/camel.h>
+#include <libebackend/libebackend.h>
+
+#include <e-util/e-util.h>
+
+#include <shell/e-shell.h>
+#include <shell/e-shell-window.h>
+
+#include <widgets/misc/e-attachment.h>
+
+#include <string.h>
+
+static gpointer parent_class = 0;
+
+struct _EMailParserPrivate {
+	GMutex *mutex;
+
+	gint last_error;
+
+	CamelSession *session;
+};
+
+#define E_MAIL_PARSER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_MAIL_PARSER, EMailParserPrivate))
+
+#define d(x)
+
+enum {
+	PROP_0,
+	PROP_SESSION
+};
+
+static GSList *
+mail_parser_run (EMailParser *parser,
+                 CamelMimeMessage *message,
+                 GCancellable *cancellable)
+{
+	GSList *parts;
+	EMailExtensionRegistry *reg;
+	GQueue *parsers;
+	GList *iter;
+	GString *part_id;
+
+	reg = e_mail_parser_get_extension_registry (parser);
+
+	parsers = e_mail_extension_registry_get_for_mime_type (
+			reg, "application/vnd.evolution.message");
+
+	if (!parsers)
+		parsers = e_mail_extension_registry_get_for_mime_type (
+			reg, "message/*");
+
+	/* parsers == NULL means, that the internal Evolution parser extensions
+	 * were not loaded. Something is terribly wrong. */
+	g_return_val_if_fail (parsers != NULL, NULL);
+
+	part_id = g_string_new (".message");
+	parts = NULL;
+
+	if (!parsers) {
+		parts = e_mail_parser_wrap_as_attachment (
+				parser, CAMEL_MIME_PART (message),
+				NULL, part_id, cancellable);
+	} else {
+		for (iter = parsers->head; iter; iter = iter->next) {
+
+			EMailParserExtension *extension;
+
+			if (g_cancellable_is_cancelled (cancellable))
+				break;
+
+			extension = iter->data;
+			if (!extension)
+				continue;
+
+			parts = e_mail_parser_extension_parse (
+					extension, parser, CAMEL_MIME_PART (message),
+					part_id, cancellable);
+
+			if (parts != NULL)
+				break;
+		}
+
+		parts = g_slist_prepend (
+				parts,
+				e_mail_part_new (
+					CAMEL_MIME_PART (message),
+					".message"));
+	}
+
+	g_string_free (part_id, TRUE);
+
+	return parts;
+}
+
+static void
+mail_parser_set_session (EMailParser *parser,
+                         CamelSession *session)
+{
+	g_return_if_fail (E_IS_MAIL_PARSER (parser));
+	g_return_if_fail (CAMEL_IS_SESSION (session));
+
+	g_object_ref (session);
+
+	if (parser->priv->session)
+		g_object_unref (parser->priv->session);
+
+	parser->priv->session = session;
+}
+
+static void
+e_mail_parser_set_property (GObject *object,
+                          guint property_id,
+                          const GValue *value,
+                          GParamSpec *pspec)
+{
+	EMailParser *parser = E_MAIL_PARSER (object);
+
+	switch (property_id) {
+		case PROP_SESSION:
+			mail_parser_set_session (parser,
+			CAMEL_SESSION (g_value_get_object (value)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_parser_get_property (GObject *object,
+                          guint property_id,
+                          GValue *value,
+                          GParamSpec *pspec)
+{
+	EMailParser *parser = E_MAIL_PARSER (object);
+
+	switch (property_id) {
+		case PROP_SESSION:
+			g_value_set_object (value,
+			G_OBJECT (e_mail_parser_get_session (parser)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_mail_parser_finalize (GObject *object)
+{
+	EMailParserPrivate *priv;
+
+	priv = E_MAIL_PARSER (object)->priv;
+
+	if (priv->mutex) {
+		g_mutex_free (priv->mutex);
+		priv->mutex = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+static void
+e_mail_parser_init (EMailParser *parser)
+{
+	parser->priv = E_MAIL_PARSER_GET_PRIVATE (parser);
+
+	parser->priv->mutex = g_mutex_new ();
+}
+
+static void
+e_mail_parser_base_init (EMailParserClass *klass)
+{
+	klass->extension_registry = g_object_new (
+		E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY, NULL);
+
+	e_mail_parser_internal_extensions_load (
+		E_MAIL_EXTENSION_REGISTRY (klass->extension_registry));
+
+	e_extensible_load_extensions (E_EXTENSIBLE (klass->extension_registry));
+}
+
+static void
+e_mail_parser_base_finalize (EMailParserClass *klass)
+{
+	g_object_unref (klass->extension_registry);
+}
+
+static void
+e_mail_parser_class_init (EMailParserClass *klass)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (EMailParserPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = e_mail_parser_finalize;
+	object_class->set_property = e_mail_parser_set_property;
+	object_class->get_property = e_mail_parser_get_property;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SESSION,
+		g_param_spec_object (
+			"session",
+			"Camel Session",
+			NULL,
+			CAMEL_TYPE_SESSION,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY));
+}
+
+GType
+e_mail_parser_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EMailParserClass),
+			(GBaseInitFunc) e_mail_parser_base_init,
+			(GBaseFinalizeFunc) e_mail_parser_base_finalize,
+			(GClassInitFunc) e_mail_parser_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EMailParser),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) e_mail_parser_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			G_TYPE_OBJECT, "EMailParser",
+			&type_info, 0);
+	}
+
+	return type;
+}
+
+EMailParser *
+e_mail_parser_new (CamelSession *session)
+{
+	return g_object_new (E_TYPE_MAIL_PARSER,
+		"session", session, NULL);
+}
+
+/**
+ * e_mail_parser_parse_sync:
+ * @parser: an #EMailParser
+ * @folder: (allow none) a #CamelFolder containing the @message or %NULL
+ * @message_uid: (allow none) UID of the @message within the @folder or %NULL
+ * @message: a #CamelMimeMessage
+ * @cancellable: (allow-none) a #GCancellable
+ *
+ * Parses the @message synchronously. Returns a list of #EMailPart<!-//>s which
+ * represents structure of the message and additional properties of each part.
+ *
+ * Note that this function can block for a while, so it's not a good idea to call
+ * it from main thread.
+ *
+ * Return Value: An #EMailPartsList
+ */
+EMailPartList *
+e_mail_parser_parse_sync (EMailParser *parser,
+                          CamelFolder *folder,
+                          const gchar *message_uid,
+                          CamelMimeMessage *message,
+                          GCancellable *cancellable)
+{
+	EMailPartList *parts_list;
+
+	g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+
+	parts_list = e_mail_part_list_new ();
+
+	if (folder)
+		parts_list->folder = g_object_ref (folder);
+
+	if (message_uid)
+		parts_list->message_uid = g_strdup (message_uid);
+
+	parts_list->message = g_object_ref (message);
+
+	parts_list->list = mail_parser_run (parser, message, cancellable);
+
+	return parts_list;
+}
+
+static void
+mail_parser_prepare_async (GSimpleAsyncResult *res,
+                           GObject *object,
+                           GCancellable *cancellable)
+{
+	CamelMimeMessage *message;
+	GSList *list;
+
+	message = g_object_get_data (G_OBJECT (res), "message");
+
+	list = mail_parser_run (E_MAIL_PARSER (object), message, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (res, list, NULL);
+}
+
+/**
+ * e_mail_parser_parse:
+ * @parser: an #EMailParser
+ * @message: a #CamelMimeMessage
+ * @callback: a #GAsyncReadyCallback
+ * @cancellable: (allow-none) a #GCancellable
+ * @user_data: (allow-none) user data passed to the callback
+ *
+ * Asynchronous version of #e_mail_parser_parse_sync().
+ */
+void
+e_mail_parser_parse (EMailParser *parser,
+                     CamelFolder *folder,
+                     const gchar *message_uid,
+                     CamelMimeMessage *message,
+                     GAsyncReadyCallback callback,
+                     GCancellable *cancellable,
+                     gpointer user_data)
+{
+	GSimpleAsyncResult *result;
+
+	g_return_if_fail (E_IS_MAIL_PARSER (parser));
+	g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+	result = g_simple_async_result_new (
+		G_OBJECT (parser), callback,
+		user_data, e_mail_parser_parse);
+
+	g_object_set_data (G_OBJECT (result), "message", g_object_ref (message));
+
+	if (folder)
+		g_object_set_data (G_OBJECT (result), "folder", g_object_ref (folder));
+	if (message_uid)
+		g_object_set_data (G_OBJECT (result), "message_uid", g_strdup (message_uid));
+
+	g_simple_async_result_run_in_thread (
+		result, mail_parser_prepare_async, G_PRIORITY_DEFAULT, cancellable);
+}
+
+EMailPartList *
+e_mail_parser_parse_finish (EMailParser *parser,
+                            GAsyncResult *result,
+                            GError **error)
+{
+	EMailPartList *parts_list;
+
+	parts_list = e_mail_part_list_new ();
+
+	/* The data were ref'ed or copied in e_mail_parser_parse_async */
+	parts_list->message = g_object_get_data (G_OBJECT (result), "message");
+	parts_list->folder = g_object_get_data (G_OBJECT (result), "folder");
+	parts_list->message_uid = g_object_get_data (G_OBJECT (result), "message_uid");
+
+	parts_list->list = g_simple_async_result_get_op_res_gpointer (
+					G_SIMPLE_ASYNC_RESULT (result));
+
+	if (camel_debug_start ("emformat:parser")) {
+		GSList *iter;
+
+		printf("%s finished with EMailPartList:\n",
+				G_OBJECT_TYPE_NAME (parser));
+
+		for (iter = parts_list->list; iter; iter = iter->next) {
+			EMailPart *part = iter->data;
+			if (!part) continue;
+			printf("	id: %s | cid: %s | mime_type: %s | is_hidden: %d | is_attachment: %d\n",
+				part->id, part->cid, part->mime_type,
+				part->is_hidden ? 1 : 0, part->is_attachment ? 1 : 0);
+		}
+
+		camel_debug_end ();
+	}
+
+	return parts_list;
+}
+
+GSList *
+e_mail_parser_parse_part (EMailParser *parser,
+                          CamelMimePart *part,
+                          GString *part_id,
+                          GCancellable *cancellable)
+{
+	CamelContentType *ct;
+	gchar *mime_type;
+	GSList *list;
+
+	ct = camel_mime_part_get_content_type (part);
+	if (!ct) {
+		mime_type = (gchar *) "application/vnd.evolution.error";
+	} else {
+		gchar *tmp;
+		tmp = camel_content_type_simple (ct);
+		mime_type = g_ascii_strdown (tmp, -1);
+		g_free (tmp);
+	}
+
+	list = e_mail_parser_parse_part_as (
+			parser, part, part_id, mime_type, cancellable);
+
+	if (ct) {
+		g_free (mime_type);
+	}
+
+	return list;
+}
+
+GSList *
+e_mail_parser_parse_part_as (EMailParser *parser,
+                             CamelMimePart *part,
+                             GString *part_id,
+                             const gchar *mime_type,
+                             GCancellable *cancellable)
+{
+	GQueue *parsers;
+	GList *iter;
+	EMailExtensionRegistry *reg;
+	EMailParserClass *parser_class;
+	GSList *part_list;
+	gchar *as_mime_type;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	if (mime_type)
+		as_mime_type = g_ascii_strdown (mime_type, -1);
+	else
+		as_mime_type = NULL;
+
+	parser_class = E_MAIL_PARSER_GET_CLASS (parser);
+	reg = E_MAIL_EXTENSION_REGISTRY (parser_class->extension_registry);
+
+	parsers = e_mail_extension_registry_get_for_mime_type (reg, as_mime_type);
+	if (!parsers) {
+		parsers = e_mail_extension_registry_get_fallback (reg, as_mime_type);
+	}
+
+	if (as_mime_type)
+		g_free (as_mime_type);
+
+	if (!parsers) {
+		return e_mail_parser_wrap_as_attachment (
+				parser, part, NULL, part_id, cancellable);
+	}
+
+	for (iter = parsers->head; iter; iter = iter->next) {
+		EMailParserExtension *extension;
+
+		extension = iter->data;
+		if (!extension)
+			continue;
+
+		part_list = e_mail_parser_extension_parse (
+				extension, parser, part, part_id, cancellable);
+
+		if (part_list)
+			break;
+	}
+
+	return part_list;
+}
+
+GSList *
+e_mail_parser_error (EMailParser *parser,
+                     GCancellable *cancellable,
+                     const gchar *format,
+                     ...)
+{
+	EMailPart *mail_part;
+	CamelMimePart *part;
+	gchar *errmsg;
+	gchar *uri;
+	va_list ap;
+
+	g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+	g_return_val_if_fail (format != NULL, NULL);
+
+	va_start (ap, format);
+	errmsg = g_strdup_vprintf (format, ap);
+
+	part = camel_mime_part_new ();
+	camel_mime_part_set_content (part,
+		errmsg, strlen (errmsg),
+		"application/vnd.evolution.error");
+	g_free (errmsg);
+	va_end (ap);
+
+	g_mutex_lock (parser->priv->mutex);
+	parser->priv->last_error++;
+	uri = g_strdup_printf (".error.%d", parser->priv->last_error);
+	g_mutex_unlock (parser->priv->mutex);
+
+	mail_part = e_mail_part_new (part, uri);
+	mail_part->mime_type = g_strdup ("application/vnd.evolution.error");
+	mail_part->is_error = TRUE;
+
+	g_free (uri);
+	g_object_unref (part);
+
+	return g_slist_append (NULL, mail_part);
+}
+
+static void
+attachment_loaded (EAttachment *attachment,
+                   GAsyncResult *res,
+                   gpointer user_data)
+{
+	EShell *shell;
+	GtkWindow *window;
+
+	shell = e_shell_get_default ();
+	window = e_shell_get_active_window (shell);
+
+	e_attachment_load_handle_error (attachment, res, window);
+
+	g_object_unref (attachment);
+}
+
+/* Idle callback */
+static gboolean
+load_attachment_idle (EAttachment *attachment)
+{
+	e_attachment_load_async (attachment,
+		(GAsyncReadyCallback) attachment_loaded, NULL);
+
+	return FALSE;
+}
+
+GSList *
+e_mail_parser_wrap_as_attachment (EMailParser *parser,
+                                  CamelMimePart *part,
+                                  GSList *parts,
+                                  GString *part_id,
+                                  GCancellable *cancellable)
+{
+	EMailPartAttachment *empa;
+	const gchar *snoop_mime_type, *cid;
+	GQueue *extensions;
+	CamelContentType *ct;
+	gchar *mime_type;
+	CamelDataWrapper *dw;
+	GByteArray *ba;
+	gsize size;
+	gint part_id_len;
+
+	ct = camel_mime_part_get_content_type (part);
+	extensions = NULL;
+	snoop_mime_type = NULL;
+	if (ct) {
+		EMailExtensionRegistry *reg;
+		mime_type = camel_content_type_simple (ct);
+
+		reg = e_mail_parser_get_extension_registry (parser);
+		extensions = e_mail_extension_registry_get_for_mime_type (
+				reg, mime_type);
+
+		if (camel_content_type_is (ct, "text", "*") ||
+		    camel_content_type_is (ct, "message", "rfc822"))
+			snoop_mime_type = mime_type;
+		else
+			g_free (mime_type);
+	}
+
+	if (!snoop_mime_type)
+		snoop_mime_type = e_mail_part_snoop_type (part);
+
+	if (parts)
+		printf("WRAPPING %s AS %s\n", E_MAIL_PART (parts->data)->id, snoop_mime_type);
+
+	if (!extensions) {
+		EMailExtensionRegistry *reg;
+
+		reg = e_mail_parser_get_extension_registry (parser);
+		extensions = e_mail_extension_registry_get_for_mime_type (
+				reg, snoop_mime_type);
+
+		if (!extensions) {
+			extensions = e_mail_extension_registry_get_fallback (
+				reg, snoop_mime_type);
+		}
+	}
+
+	part_id_len = part_id->len;
+	g_string_append (part_id, ".attachment");
+
+	empa = (EMailPartAttachment *) e_mail_part_subclass_new (
+			part, part_id->str, sizeof (EMailPartAttachment),
+			(GFreeFunc) e_mail_part_attachment_free);
+	empa->parent.mime_type = g_strdup ("application/vnd.evolution.attachment");
+	empa->parent.is_attachment = TRUE;
+	empa->shown = extensions && (!g_queue_is_empty (extensions) &&
+			e_mail_part_is_inline (part, extensions));
+	empa->snoop_mime_type = snoop_mime_type;
+	empa->attachment = e_attachment_new ();
+	empa->attachment_view_part_id = parts ? g_strdup (E_MAIL_PART (parts->data)->id) : NULL;
+
+	cid = camel_mime_part_get_content_id (part);
+	if (cid)
+		empa->parent.cid = g_strdup_printf ("cid:%s", cid);
+
+	e_attachment_set_mime_part (empa->attachment, part);
+	e_attachment_set_shown (empa->attachment, empa->shown);
+	e_attachment_set_can_show (empa->attachment,
+		extensions && !g_queue_is_empty (extensions));
+
+	/* Try to guess size of the attachments */
+	dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+	ba = camel_data_wrapper_get_byte_array (dw);
+	if (ba) {
+		size = ba->len;
+
+		if (camel_mime_part_get_encoding (part) == CAMEL_TRANSFER_ENCODING_BASE64)
+			size = size / 1.37;
+	}
+
+	/* e_attachment_load_async must be called from main thread */
+	g_idle_add (
+		(GSourceFunc) load_attachment_idle,
+		g_object_ref (empa->attachment));
+
+	if (size != 0) {
+		GFileInfo *fileinfo;
+
+		fileinfo = e_attachment_get_file_info (empa->attachment);
+
+		if (!fileinfo) {
+			fileinfo = g_file_info_new ();
+			g_file_info_set_content_type (
+				fileinfo, empa->snoop_mime_type);
+		} else {
+			g_object_ref (fileinfo);
+		}
+
+		g_file_info_set_size (fileinfo, size);
+		e_attachment_set_file_info (empa->attachment, fileinfo);
+
+		g_object_unref (fileinfo);
+	}
+
+	if (parts && parts->data) {
+		E_MAIL_PART (parts->data)->is_hidden = TRUE;
+	}
+
+	g_string_truncate (part_id, part_id_len);
+
+	return g_slist_prepend (parts, empa);
+}
+
+CamelSession *
+e_mail_parser_get_session (EMailParser *parser)
+{
+	g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+
+	return parser->priv->session;
+}
+
+EMailExtensionRegistry *
+e_mail_parser_get_extension_registry (EMailParser *parser)
+{
+	EMailParserClass *parser_class;
+
+	g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+
+	parser_class = E_MAIL_PARSER_GET_CLASS (parser);
+	return E_MAIL_EXTENSION_REGISTRY (parser_class->extension_registry);
+}
diff --git a/em-format/e-mail-parser.h b/em-format/e-mail-parser.h
new file mode 100644
index 0000000..202e28d
--- /dev/null
+++ b/em-format/e-mail-parser.h
@@ -0,0 +1,114 @@
+/*
+ * e-mail-parser.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PARSER_H_
+#define E_MAIL_PARSER_H_
+
+#include <em-format/e-mail-part-list.h>
+#include <em-format/e-mail-extension-registry.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PARSER \
+	(e_mail_parser_get_type ())
+#define E_MAIL_PARSER(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_PARSER, EMailParser))
+#define E_MAIL_PARSER_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_PARSER, EMailParserClass))
+#define E_IS_MAIL_PARSER(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_PARSER))
+#define E_IS_MAIL_PARSER_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_PARSER))
+#define E_MAIL_PARSER_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_PARSER, EMailParserClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailParser EMailParser;
+typedef struct _EMailParserClass EMailParserClass;
+typedef struct _EMailParserPrivate EMailParserPrivate;
+
+struct _EMailParser {
+	GObject parent;
+	EMailParserPrivate *priv;
+};
+
+struct _EMailParserClass {
+	GObjectClass parent_class;
+
+	EMailParserExtensionRegistry *extension_registry;
+};
+
+GType		e_mail_parser_get_type		(void);
+
+EMailParser *	e_mail_parser_new		(CamelSession *session);
+
+EMailPartList *	e_mail_parser_parse_sync	(EMailParser *parser,
+						 CamelFolder *folder,
+						 const gchar *message_uid,
+						 CamelMimeMessage *message,
+						 GCancellable  *cancellable);
+
+void		e_mail_parser_parse		(EMailParser *parser,
+						 CamelFolder *folder,
+						 const gchar *message_uid,
+						 CamelMimeMessage *message,
+						 GAsyncReadyCallback callback,
+						 GCancellable *cancellable,
+						 gpointer user_data);
+
+EMailPartList *	e_mail_parser_parse_finish	(EMailParser *parser,
+						 GAsyncResult *result,
+						 GError **error);
+
+GSList *	e_mail_parser_parse_part	(EMailParser *parser,
+						 CamelMimePart *part,
+						 GString *part_id,
+						 GCancellable *cancellable);
+
+GSList *	e_mail_parser_parse_part_as	(EMailParser *parser,
+						 CamelMimePart *part,
+						 GString *part_id,
+						 const gchar *mime_type,
+						 GCancellable *cancellable);
+
+GSList *	e_mail_parser_error		(EMailParser *parser,
+						 GCancellable *cancellable,
+						 const gchar *format,
+						 ...) G_GNUC_PRINTF (3, 4);
+
+GSList *	e_mail_parser_wrap_as_attachment
+						(EMailParser *parser,
+						 CamelMimePart *part,
+						 GSList *parts,
+						 GString *part_id,
+						 GCancellable *cancellable);
+
+CamelSession *	e_mail_parser_get_session	(EMailParser *parser);
+
+EMailExtensionRegistry *
+		e_mail_parser_get_extension_registry
+						(EMailParser *parser);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PARSER_H_ */
diff --git a/em-format/e-mail-part-attachment-bar.h b/em-format/e-mail-part-attachment-bar.h
new file mode 100644
index 0000000..e6d6542
--- /dev/null
+++ b/em-format/e-mail-part-attachment-bar.h
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_ATTACHMENT_BAR_H
+#define E_MAIL_PART_ATTACHMENT_BAR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <em-format/e-mail-part.h>
+
+#include <widgets/misc/e-attachment-store.h>
+
+typedef struct _EMailPartAttachmentBar {
+	EMailPart parent;
+
+	EAttachmentStore *store;
+} EMailPartAttachmentBar;
+
+#endif /* E_MAIL_PART_ATTACHMENT_BAR_H */
diff --git a/em-format/e-mail-part-attachment.c b/em-format/e-mail-part-attachment.c
new file mode 100644
index 0000000..2047f9d
--- /dev/null
+++ b/em-format/e-mail-part-attachment.c
@@ -0,0 +1,30 @@
+/*
+ * e-mail-part-attachment.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-part-attachment.h"
+
+void
+e_mail_part_attachment_free (EMailPartAttachment *empa)
+{
+	g_clear_object (&empa->attachment);
+
+	if (empa->attachment_view_part_id) {
+		g_free (empa->attachment_view_part_id);
+		empa->attachment_view_part_id = NULL;
+	}
+}
diff --git a/em-format/e-mail-part-attachment.h b/em-format/e-mail-part-attachment.h
new file mode 100644
index 0000000..cd07e36
--- /dev/null
+++ b/em-format/e-mail-part-attachment.h
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_ATTACHMENT_H
+#define E_MAIL_PART_ATTACHMENT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <em-format/e-mail-part.h>
+
+#define E_MAIL_PART_ATTACHMENT(p) ((EMailPartAttachment *) p)
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartAttachment {
+	EMailPart parent;
+
+	EAttachment *attachment;
+	gchar *attachment_view_part_id;
+
+	gboolean shown;
+	const gchar *snoop_mime_type;
+
+} EMailPartAttachment;
+
+void		e_mail_part_attachment_free	(EMailPartAttachment *empa);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_ATTACHMENT_H */
diff --git a/em-format/e-mail-part-list.c b/em-format/e-mail-part-list.c
new file mode 100644
index 0000000..743834b
--- /dev/null
+++ b/em-format/e-mail-part-list.c
@@ -0,0 +1,130 @@
+/*
+ * e-mail-part-list.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <camel/camel.h>
+
+#include "e-mail-part-list.h"
+
+G_DEFINE_TYPE (EMailPartList, e_mail_part_list, G_TYPE_OBJECT)
+
+static void
+unref_mail_part (gpointer user_data)
+{
+	if (user_data)
+		e_mail_part_unref (user_data);
+}
+
+static void
+e_mail_part_list_finalize (GObject *object)
+{
+	EMailPartList *part_list = E_MAIL_PART_LIST (object);
+
+	g_clear_object (&part_list->folder);
+	g_clear_object (&part_list->message);
+
+	if (part_list->list) {
+		g_slist_free_full (part_list->list, unref_mail_part);
+		part_list->list = NULL;
+	}
+
+	if (part_list->message_uid) {
+		g_free (part_list->message_uid);
+		part_list->message_uid = NULL;
+	}
+
+	G_OBJECT_CLASS (e_mail_part_list_parent_class)->finalize (object);
+}
+
+static void
+e_mail_part_list_class_init (EMailPartListClass *klass)
+{
+	GObjectClass *object_class;
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = e_mail_part_list_finalize;
+}
+
+static void
+e_mail_part_list_init (EMailPartList *part_list)
+{
+
+}
+
+EMailPartList *
+e_mail_part_list_new ()
+{
+	return g_object_new (E_TYPE_MAIL_PART_LIST, NULL);
+}
+
+EMailPart *
+e_mail_part_list_find_part (EMailPartList *part_list,
+                            const gchar *id)
+{
+	GSList *iter;
+	gboolean by_cid;
+
+	g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), NULL);
+	g_return_val_if_fail (id && *id, NULL);
+
+	by_cid = (g_str_has_prefix (id, "cid:") || g_str_has_prefix (id, "CID:"));
+
+	for (iter = part_list->list; iter; iter = iter->next) {
+
+		EMailPart *part = iter->data;
+		if (!part)
+			continue;
+
+		if ((by_cid && (g_strcmp0 (part->cid, id) == 0)) ||
+		    (!by_cid && (g_strcmp0 (part->id, id) == 0)))
+			return part;
+	}
+
+	return NULL;
+}
+
+/**
+ * e_mail_part_list_get_iter:
+ * @part_list: a #GSList of #EMailPart
+ * @id: id of #EMailPart to lookup
+ *
+ * Returns iter of an #EMailPart within the @part_list.
+ *
+ * Return Value: a #GSList sublist. The list is owned by #EMailPartList and
+ * must not be freed or altered.
+ */
+GSList *
+e_mail_part_list_get_iter (GSList *list,
+                           const gchar *id)
+{
+	GSList *iter;
+
+	g_return_val_if_fail (list != NULL, NULL);
+	g_return_val_if_fail (id && *id, NULL);
+
+	for (iter = list; iter; iter = iter->next) {
+
+		EMailPart *part = iter->data;
+		if (!part)
+			continue;
+
+		if (g_strcmp0 (part->id, id) == 0)
+			return iter;
+	}
+
+	return NULL;
+}
diff --git a/em-format/e-mail-part-list.h b/em-format/e-mail-part-list.h
new file mode 100644
index 0000000..12a24f3
--- /dev/null
+++ b/em-format/e-mail-part-list.h
@@ -0,0 +1,76 @@
+/*
+ * e-mail-part-list.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_LIST_H_
+#define E_MAIL_PART_LIST_H_
+
+#include <camel/camel.h>
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_LIST \
+	(e_mail_part_list_get_type ())
+#define E_MAIL_PART_LIST(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_PART_LIST, EMailPartList))
+#define E_MAIL_PART_LIST_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_PART_LIST, EMailPartListClass))
+#define E_IS_MAIL_PART_LIST(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_PART_LIST))
+#define E_IS_MAIL_PART_LIST_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_PART_LIST))
+#define E_MAIL_PART_LIST_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_PART_LIST, EMailPartListClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartList EMailPartList;
+typedef struct _EMailPartListClass EMailPartListClass;
+
+struct _EMailPartList {
+	GObject parent;
+
+	CamelMimeMessage *message;
+	CamelFolder *folder;
+	gchar *message_uid;
+
+	/* GSList of EMailPart's */
+	GSList *list;
+};
+
+struct _EMailPartListClass {
+	GObjectClass parent_class;
+};
+
+EMailPartList *	e_mail_part_list_new		();
+
+GType		e_mail_part_list_get_type	();
+
+EMailPart *	e_mail_part_list_find_part	(EMailPartList *part_list,
+						 const gchar *id);
+
+GSList *		e_mail_part_list_get_iter	(GSList *list,
+						 const gchar *id);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_LIST_H_ */ 
diff --git a/em-format/e-mail-part-utils.c b/em-format/e-mail-part-utils.c
new file mode 100644
index 0000000..858209b
--- /dev/null
+++ b/em-format/e-mail-part-utils.c
@@ -0,0 +1,546 @@
+/*
+ * e-mail-part-utils.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include "e-mail-part-utils.h"
+#include "e-mail-parser-extension.h"
+
+#include <camel/camel.h>
+#include <e-util/e-util.h>
+#include <gdk/gdk.h>
+
+#include <libsoup/soup.h>
+
+#include <string.h>
+
+#define d(x)
+
+/**
+ * e_mail_parst_is_secured:
+ * @part: a #CamelMimePart
+ *
+ * Whether @part is signed or encrypted or not.
+ *
+ * Return Value: TRUE/FALSE
+ */
+gboolean
+e_mail_part_is_secured (CamelMimePart *part)
+{
+	CamelContentType *ct = camel_mime_part_get_content_type (part);
+
+	return (camel_content_type_is (ct, "multipart", "signed") ||
+		camel_content_type_is (ct, "multipart", "encrypted") ||
+		camel_content_type_is (ct, "application", "x-inlinepgp-signed") ||
+		camel_content_type_is (ct, "application", "x-inlinepgp-encrypted") ||
+		camel_content_type_is (ct, "application", "x-pkcs7-mime") ||
+		camel_content_type_is (ct, "application", "pkcs7-mime"));
+}
+
+/**
+ * e_mail_partr_snoop_type:
+ * @part: a #CamelMimePart
+ *
+ * Tries to snoop the mime type of a part.
+ *
+ * Return value: %NULL if unknown (more likely application/octet-stream).
+ **/
+const gchar *
+e_mail_part_snoop_type (CamelMimePart *part)
+{
+	/* cache is here only to be able still return const gchar * */
+	static GHashTable *types_cache = NULL;
+
+	const gchar *filename;
+	gchar *name_type = NULL, *magic_type = NULL, *res, *tmp;
+	CamelDataWrapper *dw;
+
+	filename = camel_mime_part_get_filename (part);
+	if (filename != NULL)
+		name_type = e_util_guess_mime_type (filename, FALSE);
+
+	dw = camel_medium_get_content ((CamelMedium *) part);
+	if (!camel_data_wrapper_is_offline (dw)) {
+		GByteArray *byte_array;
+		CamelStream *stream;
+
+		byte_array = g_byte_array_new ();
+		stream = camel_stream_mem_new_with_byte_array (byte_array);
+
+		if (camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL) > 0) {
+			gchar *content_type;
+
+			content_type = g_content_type_guess (
+				filename, byte_array->data,
+				byte_array->len, NULL);
+
+			if (content_type != NULL)
+				magic_type = g_content_type_get_mime_type (content_type);
+
+			g_free (content_type);
+		}
+
+		g_object_unref (stream);
+	}
+
+	/* If gvfs doesn't recognize the data by magic, but it
+	 * contains English words, it will call it text/plain. If the
+	 * filename-based check came up with something different, use
+	 * that instead and if it returns "application/octet-stream"
+	 * try to do better with the filename check.
+	 */
+
+	if (magic_type) {
+		if (name_type
+		    && (!strcmp(magic_type, "text/plain")
+			|| !strcmp(magic_type, "application/octet-stream")))
+			res = name_type;
+		else
+			res = magic_type;
+	} else
+		res = name_type;
+
+	if (res != name_type)
+		g_free (name_type);
+
+	if (res != magic_type)
+		g_free (magic_type);
+
+	if (!types_cache)
+		types_cache = g_hash_table_new_full (
+			g_str_hash, g_str_equal,
+			(GDestroyNotify) g_free,
+			(GDestroyNotify) NULL);
+
+	if (res) {
+		tmp = g_hash_table_lookup (types_cache, res);
+		if (tmp) {
+			g_free (res);
+			res = tmp;
+		} else {
+			g_hash_table_insert (types_cache, res, res);
+		}
+	}
+
+	d(printf("Snooped mime type %s\n", res));
+	return res;
+
+	/* We used to load parts to check their type, we don't anymore,
+	 * see bug #211778 for some discussion */
+}
+
+/**
+ * e_mail_part_is_attachment
+ * @part: Part to check.
+ *
+ * Returns true if the part is an attachment.
+ *
+ * A part is not considered an attachment if it is a
+ * multipart, or a text part with no filename.  It is used
+ * to determine if an attachment header should be displayed for
+ * the part.
+ *
+ * Content-Disposition is not checked.
+ *
+ * Return value: TRUE/FALSE
+ **/
+gboolean
+e_mail_part_is_attachment (CamelMimePart *part)
+{
+	/*CamelContentType *ct = camel_mime_part_get_content_type(part);*/
+	CamelDataWrapper *dw = camel_medium_get_content ((CamelMedium *) part);
+
+	if (!dw)
+		return 0;
+
+	d(printf("checking is attachment %s/%s\n", dw->mime_type->type, dw->mime_type->subtype));
+	return !(camel_content_type_is (dw->mime_type, "multipart", "*")
+		 || camel_content_type_is (
+			dw->mime_type, "application", "x-pkcs7-mime")
+		 || camel_content_type_is (
+			dw->mime_type, "application", "pkcs7-mime")
+		 || camel_content_type_is (
+			dw->mime_type, "application", "x-inlinepgp-signed")
+		 || camel_content_type_is (
+			dw->mime_type, "application", "x-inlinepgp-encrypted")
+		 || camel_content_type_is (
+			dw->mime_type, "x-evolution", "evolution-rss-feed")
+		 || camel_content_type_is (dw->mime_type, "text", "calendar")
+		 || camel_content_type_is (dw->mime_type, "text", "x-calendar")
+		 || (camel_content_type_is (dw->mime_type, "text", "*")
+		     && camel_mime_part_get_filename (part) == NULL));
+}
+
+/**
+ * e_mail_part_preserve_charset_in_content_type:
+ * @ipart: Source #CamelMimePart
+ * @opart: Target #CamelMimePart
+ *
+ * Copies 'charset' part of content-type header from @ipart to @opart.
+ */
+void
+e_mail_part_preserve_charset_in_content_type (CamelMimePart *ipart,
+                                              CamelMimePart *opart)
+{
+	CamelDataWrapper *data_wrapper;
+	CamelContentType *content_type;
+	const gchar *charset;
+
+	g_return_if_fail (ipart != NULL);
+	g_return_if_fail (opart != NULL);
+
+	data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (ipart));
+	content_type = camel_data_wrapper_get_mime_type_field (data_wrapper);
+
+	if (content_type == NULL)
+		return;
+
+	charset = camel_content_type_param (content_type, "charset");
+
+	if (charset == NULL || *charset == '\0')
+		return;
+
+	data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (opart));
+	content_type = camel_data_wrapper_get_mime_type_field (data_wrapper);
+
+	if (content_type)
+		camel_content_type_set_param (content_type, "charset", charset);
+
+	/* update charset also on the part itself */
+	data_wrapper = CAMEL_DATA_WRAPPER (opart);
+	content_type = camel_data_wrapper_get_mime_type_field (data_wrapper);
+	if (content_type)
+		camel_content_type_set_param (content_type, "charset", charset);
+}
+
+/**
+ * e_mail_part_get_related_display_part:
+ * @part: a multipart/related or multipart/alternative #CamelMimePart
+ * @out_displayid: (out) returns index of the returned part
+ *
+ * Goes through all subparts of given @part and tries to determine which
+ * part should be displayed and which parts are just attachments to the
+ * part.
+ *
+ * Return Value: A #CamelMimePart that should be displayed
+ */
+CamelMimePart *
+e_mail_part_get_related_display_part (CamelMimePart *part,
+                                      gint *out_displayid)
+{
+	CamelMultipart *mp;
+	CamelMimePart *body_part, *display_part = NULL;
+	CamelContentType *content_type;
+	const gchar *start;
+	gint i, nparts, displayid = 0;
+
+	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
+
+	if (!CAMEL_IS_MULTIPART (mp))
+		return NULL;
+
+	nparts = camel_multipart_get_number (mp);
+	content_type = camel_mime_part_get_content_type (part);
+	start = camel_content_type_param (content_type, "start");
+	if (start && strlen (start) > 2) {
+		gint len;
+		const gchar *cid;
+
+		/* strip <>'s from CID */
+		len = strlen (start) - 2;
+		start++;
+
+		for (i = 0; i < nparts; i++) {
+			body_part = camel_multipart_get_part (mp, i);
+			cid = camel_mime_part_get_content_id (body_part);
+
+			if (cid && !strncmp (cid, start, len) && strlen (cid) == len) {
+				display_part = body_part;
+				displayid = i;
+				break;
+			}
+		}
+	} else {
+		display_part = camel_multipart_get_part (mp, 0);
+	}
+
+	if (out_displayid)
+		*out_displayid = displayid;
+
+	return display_part;
+}
+
+void
+e_mail_part_animation_extract_frame (const GByteArray *anim,
+                                     gchar **frame,
+                                     gsize *len)
+{
+	GdkPixbufLoader *loader;
+	GdkPixbufAnimation *animation;
+	GdkPixbuf *frame_buf;
+
+        /* GIF89a (GIF image signature) */
+	const gchar GIF_HEADER[] = { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 };
+	const gint   GIF_HEADER_LEN = sizeof (GIF_HEADER);
+
+        /* NETSCAPE2.0 (extension describing animated GIF, starts on 0x310) */
+	const gchar GIF_APPEXT[] = { 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41,
+				     0x50, 0x45, 0x32, 0x2E, 0x30 };
+	const gint   GIF_APPEXT_LEN = sizeof (GIF_APPEXT);
+
+	if ((anim == NULL) || (anim->data == NULL)) {
+		*frame = NULL;
+		*len = 0;
+		return;
+	}
+
+        /* Check if the image is an animated GIF. We don't care about any
+         * other animated formats (APNG or MNG) as WebKit does not support them
+         * and displays only the first frame. */
+	if ((anim->len < 0x331)
+	    || (memcmp (anim->data, GIF_HEADER, GIF_HEADER_LEN) != 0)
+	    || (memcmp (&anim->data[0x310], GIF_APPEXT, GIF_APPEXT_LEN) != 0)) {
+
+                *frame = g_memdup (anim->data, anim->len);
+                *len = anim->len;
+		return;
+	}
+
+	loader = gdk_pixbuf_loader_new ();
+	gdk_pixbuf_loader_write (loader, (guchar *) anim->data, anim->len, NULL);
+	gdk_pixbuf_loader_close (loader, NULL);
+	animation = gdk_pixbuf_loader_get_animation (loader);
+	if (!animation) {
+
+                *frame = g_memdup (anim->data, anim->len);
+                *len = anim->len;
+		g_object_unref (loader);
+		return;
+	}
+
+        /* Extract first frame */
+	frame_buf = gdk_pixbuf_animation_get_static_image (animation);
+	if (!frame_buf) {
+                *frame = g_memdup (anim->data, anim->len);
+                *len = anim->len;
+		g_object_unref (loader);
+		g_object_unref (animation);
+		return;
+	}
+
+        /* Unforunatelly, GdkPixbuf cannot save to GIF, but WebKit does not
+         * have any trouble displaying PNG image despite the part having
+         * image/gif mime-type */
+	gdk_pixbuf_save_to_buffer (frame_buf, frame, len, "png", NULL, NULL);
+
+	g_object_unref (loader);
+}
+
+/**
+ * e_mail_part_build_url:
+ * @folder: (allow-none) a #CamelFolder with the message or %NULL
+ * @message_uid: (allow-none) uid of the message within the @folder or %NULL
+ * @first_param_name: Name of first query parameter followed by GType of it's value and value
+ * terminated by %NULL.
+ *
+ * Construct a URI for message.
+ *
+ * The URI can contain multiple query parameters. The list of parameters must be
+ * NULL-terminated. Each query must contain name, GType of value and value.
+ *
+ * Return Value: a URL of a message or part
+ */
+gchar *
+e_mail_part_build_uri (CamelFolder *folder,
+                       const gchar *message_uid,
+                       const gchar *first_param_name,
+                       ...)
+{
+	CamelStore *store;
+	gchar *uri, *tmp;
+	va_list ap;
+	const gchar *name;
+	const gchar *service_uid, *folder_name;
+	gchar separator;
+
+	g_return_val_if_fail (message_uid && *message_uid, NULL);
+
+	if (!folder) {
+		folder_name = "generic";
+		service_uid = "generic";
+	} else {
+		tmp = (gchar *) camel_folder_get_full_name (folder);
+		folder_name = (const gchar *) soup_uri_encode (tmp, NULL);
+		store = camel_folder_get_parent_store (folder);
+		if (store)
+			service_uid = camel_service_get_uid (CAMEL_SERVICE (store));
+		else
+			service_uid = "generic";
+	}
+
+	tmp = g_strdup_printf ("mail://%s/%s/%s",
+			service_uid,
+			folder_name,
+			message_uid);
+
+	if (folder) {
+		g_free ((gchar *) folder_name);
+	}
+
+	va_start (ap, first_param_name);
+	name = first_param_name;
+	separator = '?';
+	while (name) {
+		gchar *tmp2;
+		gint type = va_arg (ap, gint);
+		switch (type) {
+			case G_TYPE_INT:
+			case G_TYPE_BOOLEAN: {
+				gint val = va_arg (ap, gint);
+				tmp2 = g_strdup_printf ("%s%c%s=%d", tmp,
+						separator, name, val);
+				break;
+			}
+			case G_TYPE_FLOAT:
+			case G_TYPE_DOUBLE: {
+				gdouble val = va_arg (ap, double);
+				tmp2 = g_strdup_printf ("%s%c%s=%f", tmp,
+						separator, name, val);
+				break;
+			}
+			case G_TYPE_STRING: {
+				gchar *val = va_arg (ap, gchar *);
+				gchar *escaped = soup_uri_encode (val, NULL);
+				tmp2 = g_strdup_printf ("%s%c%s=%s", tmp,
+						separator, name, escaped);
+				g_free (escaped);
+				break;
+			}
+			default:
+				g_warning ("Invalid param type %s", g_type_name (type));
+				return NULL;
+		}
+
+		g_free (tmp);
+		tmp = tmp2;
+
+		if (separator == '?')
+			separator = '&';
+
+		name = va_arg (ap, gchar *);
+	}
+	va_end (ap);
+
+	uri = tmp;
+	if (uri == NULL)
+		return NULL;
+
+	/* For some reason, webkit won't accept URL with username, but
+	 * without password (mail://store host/folder/mail), so we
+	 * will replace the '@' symbol by '/' to get URL like
+	 * mail://store/host/folder/mail which is OK
+	 */
+	while ((tmp = strchr (uri, '@')) != NULL) {
+		tmp[0] = '/';
+	}
+
+	return uri;
+}
+
+/**
+ * e_mail_part_describe:
+ * @part: a #CamelMimePart
+ * @mimetype: mimetype of the content
+ *
+ * Generate a simple textual description of a part, @mime_type represents
+ * the content.
+ *
+ * Return value:
+ **/
+gchar *
+e_mail_part_describe (CamelMimePart *part,
+                      const gchar *mime_type)
+{
+	GString *stext;
+	const gchar *filename, *description;
+	gchar *content_type, *desc;
+
+	stext = g_string_new("");
+	content_type = g_content_type_from_mime_type (mime_type);
+	desc = g_content_type_get_description (
+		content_type != NULL ? content_type : mime_type);
+	g_free (content_type);
+	g_string_append_printf (
+		stext, _("%s attachment"), desc ? desc : mime_type);
+	g_free (desc);
+
+	filename = camel_mime_part_get_filename (part);
+	description = camel_mime_part_get_description (part);
+
+	if (!filename || !*filename) {
+		CamelDataWrapper *content;
+
+		content = camel_medium_get_content (CAMEL_MEDIUM (part));
+
+		if (CAMEL_IS_MIME_MESSAGE (content))
+			filename = camel_mime_message_get_subject (
+				CAMEL_MIME_MESSAGE (content));
+	}
+
+	if (filename != NULL && *filename != '\0') {
+		gchar *basename = g_path_get_basename (filename);
+		g_string_append_printf (stext, " (%s)", basename);
+		g_free (basename);
+	}
+
+	if (description != NULL && *description != '\0' &&
+		g_strcmp0 (filename, description) != 0)
+		g_string_append_printf (stext, ", \"%s\"", description);
+
+	return g_string_free (stext, FALSE);
+}
+
+gboolean
+e_mail_part_is_inline (CamelMimePart *mime_part,
+                       GQueue *extensions)
+{
+	const gchar *disposition;
+	EMailParserExtension *extension;
+
+	if ((extensions == NULL) || g_queue_is_empty (extensions))
+		return FALSE;
+
+	extension = g_queue_peek_head (extensions);
+	/* Some types need to override the disposition.
+	 * e.g. application/x-pkcs7-mime */
+	if (e_mail_parser_extension_get_flags (extension) &
+		E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION)
+		return TRUE;
+
+	disposition = camel_mime_part_get_disposition (mime_part);
+	if (disposition != NULL)
+		return g_ascii_strcasecmp (disposition, "inline") == 0;
+
+	/* Otherwise, use the default for this handler type. */
+	return (e_mail_parser_extension_get_flags (extension) &
+			E_MAIL_PARSER_EXTENSION_INLINE) != 0;
+}
diff --git a/em-format/e-mail-part-utils.h b/em-format/e-mail-part-utils.h
new file mode 100644
index 0000000..97c483d
--- /dev/null
+++ b/em-format/e-mail-part-utils.h
@@ -0,0 +1,58 @@
+/*
+ * e-mail-part-utils.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_UTILS_H_
+#define E_MAIL_PART_UTILS_H_
+
+#include <camel/camel.h>
+
+G_BEGIN_DECLS
+
+gboolean	e_mail_part_is_secured		(CamelMimePart *part);
+
+const gchar *	e_mail_part_snoop_type		(CamelMimePart *part);
+
+gboolean	e_mail_part_is_attachment	(CamelMimePart *part);
+
+void		e_mail_part_preserve_charset_in_content_type
+						(CamelMimePart *ipart,
+						 CamelMimePart *opart);
+
+CamelMimePart *	e_mail_part_get_related_display_part
+						(CamelMimePart *part,
+						 gint *out_displayid);
+
+void		e_mail_part_animation_extract_frame (
+						const GByteArray *anim,
+						gchar **frame,
+						gsize *len);
+
+gchar *		e_mail_part_build_uri		(CamelFolder *folder,
+						 const gchar *message_uid,
+						 const gchar *first_param_name,
+						 ...);
+
+gchar *		e_mail_part_describe		(CamelMimePart *part,
+						 const gchar *mime_type);
+
+gboolean	e_mail_part_is_inline		(CamelMimePart *part,
+						 GQueue *extensions);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_UTILS_H_ */
diff --git a/em-format/e-mail-part.c b/em-format/e-mail-part.c
new file mode 100644
index 0000000..a0d493a
--- /dev/null
+++ b/em-format/e-mail-part.c
@@ -0,0 +1,196 @@
+/*
+ * e-mail-part.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <camel/camel.h>
+
+#include "e-mail-part.h"
+
+/**
+ * EMailPart:
+ *
+ * The #EMailPart is a wrapper around #CamelMimePart which holds additional
+ * information about the mime part, like it's ID, encryption type etc.
+ *
+ * #EMailPart is not GObject-based, but has a simple reference counting.
+ *
+ * Each #EMailPart must have a unique ID. The ID is a dot-separated hierarchical
+ * description of the location of the part within the email message.
+ */
+
+struct _EMailPartPrivate {
+	guint ref_cnt;
+	gsize instance_size;
+	GFreeFunc free_func;
+};
+
+static void
+mail_part_free (EMailPart *part)
+{
+	if (!part)
+		return;
+
+	if (part->part) {
+		g_object_unref (part->part);
+		part->part = NULL;
+	}
+
+	if (part->cid) {
+		g_free (part->cid);
+		part->cid = NULL;
+	}
+
+	if (part->mime_type) {
+		g_free (part->mime_type);
+		part->mime_type = NULL;
+	}
+
+	if (part->validity) {
+		camel_cipher_validity_free (part->validity);
+		part->validity = NULL;
+	}
+
+	if (part->validity_parent) {
+		camel_cipher_validity_free (part->validity_parent);
+		part->validity_parent = NULL;
+	}
+
+	if (part->priv->free_func) {
+		part->priv->free_func (part);
+		part->priv->free_func = NULL;
+	}
+
+	if (part->id) {
+		g_free (part->id);
+		part->id = NULL;
+	}
+
+	g_free (part->priv);
+	part->priv = NULL;
+
+	g_free (part);
+}
+
+/**
+ * e_mail_part_new:
+ * @part: (allow-none) a #CamelMimePart or %NULL
+ * @id: part ID
+ *
+ * Creates a new #EMailPart for given mime part.
+ *
+ * Return value: a new #EMailPart
+ */
+EMailPart *
+e_mail_part_new (CamelMimePart *part,
+                 const gchar *id)
+{
+	return e_mail_part_subclass_new (part, id, sizeof (EMailPart), NULL);
+}
+
+/**
+ * e_mail_part_new:
+ * @part: (allow-none) a #CamelMimePart or %NULL
+ * @id: part ID
+ * @size: Size of the EMailPart subclass
+ *
+ * Allocates a @size bytes representing an #EMailPart subclass.
+ *
+ * Return value: a new #EMailPart-based object
+ */
+EMailPart *
+e_mail_part_subclass_new (CamelMimePart *part,
+                          const gchar *id,
+                          gsize size,
+                          GFreeFunc free_func)
+{
+	EMailPart *mail_part;
+
+	g_return_val_if_fail (size >= sizeof (EMailPart), NULL);
+
+	mail_part = g_malloc0 (size);
+	mail_part->priv = g_new0 (EMailPartPrivate, 1);
+
+	mail_part->priv->ref_cnt = 1;
+	mail_part->priv->free_func = free_func;
+	mail_part->priv->instance_size = size;
+
+	if (part) {
+		mail_part->part = g_object_ref (part);
+	}
+
+	if (id) {
+		mail_part->id = g_strdup (id);
+	}
+
+	return mail_part;
+}
+
+EMailPart *
+e_mail_part_ref (EMailPart *part)
+{
+	g_return_val_if_fail (part != NULL, NULL);
+	g_return_val_if_fail (part->priv != NULL, NULL);
+
+	g_atomic_int_inc (&part->priv->ref_cnt);
+
+	return part;
+}
+
+void
+e_mail_part_unref (EMailPart *part)
+{
+	g_return_if_fail (part != NULL);
+	g_return_if_fail (part->priv != NULL);
+
+	if (g_atomic_int_dec_and_test (&part->priv->ref_cnt)) {
+		mail_part_free (part);
+	}
+}
+
+gsize
+e_mail_part_get_instance_size (EMailPart *part)
+{
+	g_return_val_if_fail (part != NULL, 0);
+
+	return part->priv->instance_size;
+}
+
+/**
+ * e_mail_part_update_validity:
+ * @part: An #EMailPart
+ * @validity_type: E_MAIL_PART_VALIDITY_* flags
+ * @validity: a #CamelCipherValidity
+ *
+ * Updates validity of the @part. When the part already has some validity
+ * set, the new @validity and @validity_type are just appended, preserving
+ * the original validity.
+ */
+void
+e_mail_part_update_validity (EMailPart *part,
+                             CamelCipherValidity *validity,
+                             guint32 validity_type)
+{
+	g_return_if_fail (part != NULL);
+
+	part->validity_type &= validity_type;
+
+	if (part->validity) {
+		camel_cipher_validity_envelope (part->validity, validity);
+	} else {
+		part->validity = camel_cipher_validity_clone (validity);
+	}
+}
diff --git a/em-format/e-mail-part.h b/em-format/e-mail-part.h
new file mode 100644
index 0000000..3d2e962
--- /dev/null
+++ b/em-format/e-mail-part.h
@@ -0,0 +1,98 @@
+/*
+ * e-mail-part.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PART_H_
+#define E_MAIL_PART_H_
+
+#include <camel/camel.h>
+#include <misc/e-attachment.h>
+#include <webkit/webkitdom.h>
+
+#define E_MAIL_PART_IS(p,s_t) \
+		((p != NULL) && (e_mail_part_get_instance_size (p) == sizeof (s_t)))
+#define E_MAIL_PART(o) ((EMailPart *) o)
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPart EMailPart;
+typedef struct _EMailPartPrivate EMailPartPrivate;
+
+typedef void	(*EMailPartDOMBindFunc)	(EMailPart *part,
+					 WebKitDOMElement *element);
+
+enum {
+	E_MAIL_PART_VALIDITY_NONE	=	0,
+	E_MAIL_PART_VALIDITY_PGP	=	1 << 0,
+	E_MAIL_PART_VALIDITY_SMIME	=	1 << 1,
+	E_MAIL_PART_VALIDITY_SIGNED	=	1 << 2,
+	E_MAIL_PART_VALIDITY_ENCRYPTED	=	1 << 3
+} EMailPartValidityFlags;
+
+struct _EMailPart {
+	EMailPartPrivate *priv;
+
+	EMailPartDOMBindFunc bind_func;
+
+	CamelMimePart *part;
+	gchar *id;
+	gchar *cid;
+	gchar *mime_type;
+
+	guint32 validity_type;	/* E_MAIL_PART_VALIDITY_ * flags */
+	CamelCipherValidity *validity;
+	CamelCipherValidity *validity_parent;
+
+	gint is_attachment: 1;
+
+	/* Whether the part should be rendered or not.
+	 * This is used for example to prevent images
+	 * related to text/html parts from being
+	 * rendered as attachments. */
+	gint is_hidden: 1;
+
+	/* Force attachment to be expanded, even without
+	 * content-disposition: inline */
+	gint force_inline: 1;
+
+	/* Force attachment to be collapsed, even with
+	 * content-disposition: inline */
+	gint force_collapse: 1;
+
+	/* Does part contain an error message? */
+	gint is_error: 1;
+};
+
+EMailPart *	e_mail_part_new			(CamelMimePart *part,
+						 const gchar *id);
+EMailPart *	e_mail_part_subclass_new	(CamelMimePart *part,
+						 const gchar *id,
+						 gsize size,
+						 GFreeFunc free_func);
+
+EMailPart *	e_mail_part_ref			(EMailPart *part);
+void		e_mail_part_unref		(EMailPart *part);
+
+gsize		e_mail_part_get_instance_size	(EMailPart *part);
+
+void		e_mail_part_update_validity	(EMailPart *part,
+						 CamelCipherValidity *validity,
+						 guint32 validity_type);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_H_ */
diff --git a/em-format/em-stripsig-filter.c b/em-format/e-mail-stripsig-filter.c
similarity index 86%
rename from em-format/em-stripsig-filter.c
rename to em-format/e-mail-stripsig-filter.c
index fe08383..e861a13 100644
--- a/em-format/em-stripsig-filter.c
+++ b/em-format/e-mail-stripsig-filter.c
@@ -28,9 +28,9 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "em-stripsig-filter.h"
+#include "e-mail-stripsig-filter.h"
 
-G_DEFINE_TYPE (EMStripSigFilter, em_stripsig_filter, CAMEL_TYPE_MIME_FILTER)
+G_DEFINE_TYPE (EMailStripSigFilter, e_mail_stripsig_filter, CAMEL_TYPE_MIME_FILTER)
 
 static void
 strip_signature (CamelMimeFilter *filter,
@@ -42,7 +42,7 @@ strip_signature (CamelMimeFilter *filter,
                  gsize *outprespace,
                  gint flush)
 {
-	EMStripSigFilter *stripsig = (EMStripSigFilter *) filter;
+	EMailStripSigFilter *stripsig = (EMailStripSigFilter *) filter;
 	register const gchar *inptr = in;
 	const gchar *inend = in + len;
 	const gchar *start = NULL;
@@ -124,13 +124,13 @@ filter_complete (CamelMimeFilter *filter,
 static void
 filter_reset (CamelMimeFilter *filter)
 {
-	EMStripSigFilter *stripsig = (EMStripSigFilter *) filter;
+	EMailStripSigFilter *stripsig = (EMailStripSigFilter *) filter;
 
 	stripsig->midline = FALSE;
 }
 
 static void
-em_stripsig_filter_class_init (EMStripSigFilterClass *class)
+e_mail_stripsig_filter_class_init (EMailStripSigFilterClass *class)
 {
 	CamelMimeFilterClass *mime_filter_class;
 
@@ -141,12 +141,12 @@ em_stripsig_filter_class_init (EMStripSigFilterClass *class)
 }
 
 static void
-em_stripsig_filter_init (EMStripSigFilter *filter)
+e_mail_stripsig_filter_init (EMailStripSigFilter *filter)
 {
 }
 
 /**
- * em_stripsig_filter_new:
+ * e_mail_stripsig_filter_new:
  * @text_plain_only: Whether should look for a text/plain signature
  * delimiter "-- \n" only or also an HTML signature delimiter "-- <BR>".
  *
@@ -155,9 +155,9 @@ em_stripsig_filter_init (EMStripSigFilter *filter)
  * Returns a new stripsig filter.
  **/
 CamelMimeFilter *
-em_stripsig_filter_new (gboolean text_plain_only)
+e_mail_stripsig_filter_new (gboolean text_plain_only)
 {
-	EMStripSigFilter *filter = g_object_new (EM_TYPE_STRIPSIG_FILTER, NULL);
+	EMailStripSigFilter *filter = g_object_new (E_TYPE_MAIL_STRIPSIG_FILTER, NULL);
 
 	filter->text_plain_only = text_plain_only;
 
diff --git a/em-format/em-stripsig-filter.h b/em-format/e-mail-stripsig-filter.h
similarity index 54%
rename from em-format/em-stripsig-filter.h
rename to em-format/e-mail-stripsig-filter.h
index 47017f7..730d55e 100644
--- a/em-format/em-stripsig-filter.h
+++ b/em-format/e-mail-stripsig-filter.h
@@ -20,50 +20,50 @@
  *
  */
 
-#ifndef EM_STRIPSIG_FILTER_H
-#define EM_STRIPSIG_FILTER_H
+#ifndef E_MAIL_STRIPSIG_FILTER_H
+#define E_MAIL_STRIPSIG_FILTER_H
 
 #include <camel/camel.h>
 
 /* Standard GObject macros */
-#define EM_TYPE_STRIPSIG_FILTER \
-	(em_stripsig_filter_get_type ())
-#define EM_STRIPSIG_FILTER(obj) \
+#define E_TYPE_MAIL_STRIPSIG_FILTER \
+	(e_mail_stripsig_filter_get_type ())
+#define E_MAIL_STRIPSIG_FILTER(obj) \
 	(G_TYPE_CHECK_INSTANCE_CAST \
-	((obj), EM_TYPE_STRIPSIG_FILTER, EMStripSigFilter))
-#define EM_STRIPSIG_FILTER_CLASS(cls) \
+	((obj), E_TYPE_MAIL_STRIPSIG_FILTER, EMailStripSigFilter))
+#define E_MAIL_STRIPSIG_FILTER_CLASS(cls) \
 	(G_TYPE_CHECK_CLASS_CAST \
-	((cls), EM_TYPE_STRIPSIG_FILTER, EMStripSigFilterClass))
-#define EM_IS_STRIPSIG_FILTER(obj) \
+	((cls), E_TYPE_MAIL_STRIPSIG_FILTER, EMailStripSigFilterClass))
+#define E_MAIL_IS_STRIPSIG_FILTER(obj) \
 	(G_TYPE_CHECK_INSTANCE_TYPE \
-	((obj), EM_TYPE_STRIPSIG_FILTER))
-#define EM_IS_STRIPSIG_FILTER_CLASS(cls) \
+	((obj), E_TYPE_MAIL_STRIPSIG_FILTER))
+#define E_MAIL_IS_STRIPSIG_FILTER_CLASS(cls) \
 	(G_TYPE_CHECK_CLASS_TYPE \
-	((cls), EM_TYPE_STRIPSIG_FILTER))
-#define EM_STRIPSIG_FILTER_GET_CLASS(obj) \
+	((cls), E_TYPE_MAIL_STRIPSIG_FILTER))
+#define E_MAIL_STRIPSIG_FILTER_GET_CLASS(obj) \
 	(G_TYPE_INSTANCE_GET_CLASS \
-	((obj), EM_TYPE_STRIPSIG_FILTER, EMStripSigFilterClass))
+	((obj), E_TYPE_MAIL_STRIPSIG_FILTER, EMailStripSigFilterClass))
 
 G_BEGIN_DECLS
 
-typedef struct _EMStripSigFilter EMStripSigFilter;
-typedef struct _EMStripSigFilterClass EMStripSigFilterClass;
+typedef struct _EMailStripSigFilter EMailStripSigFilter;
+typedef struct _EMailStripSigFilterClass EMailStripSigFilterClass;
 
-struct _EMStripSigFilter {
+struct _EMailStripSigFilter {
 	CamelMimeFilter parent;
 
 	guint32 midline : 1;
 	guint32 text_plain_only : 1;
 };
 
-struct _EMStripSigFilterClass {
+struct _EMailStripSigFilterClass {
 	CamelMimeFilterClass parent_class;
 };
 
-GType		em_stripsig_filter_get_type	(void);
+GType		e_mail_stripsig_filter_get_type	(void);
 CamelMimeFilter *
-		em_stripsig_filter_new		(gboolean text_plain_only);
+		e_mail_stripsig_filter_new	(gboolean text_plain_only);
 
 G_END_DECLS
 
-#endif /* EM_STRIPSIG_FILTER_H */
+#endif /* E_MAIL_STRIPSIG_FILTER_H */
diff --git a/mail/Makefile.am b/mail/Makefile.am
index da2c0eb..7fa3dba 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -44,7 +44,6 @@ mailinclude_HEADERS =					\
 	e-mail-account-manager.h			\
 	e-mail-account-store.h				\
 	e-mail-account-tree-view.h			\
-	e-mail-attachment-bar.h				\
 	e-mail-autoconfig.h				\
 	e-mail-backend.h				\
 	e-mail-browser.h				\
@@ -101,10 +100,6 @@ mailinclude_HEADERS =					\
 	em-folder-tree-model.h				\
 	em-folder-tree.h				\
 	em-folder-utils.h				\
-	em-format-hook.h				\
-	em-format-html-display.h			\
-	em-format-html-print.h				\
-	em-format-html.h				\
 	em-search-context.h				\
 	em-subscription-editor.h			\
 	em-utils.h					\
@@ -128,7 +123,6 @@ libevolution_mail_la_SOURCES =				\
 	e-mail-account-manager.c			\
 	e-mail-account-store.c				\
 	e-mail-account-tree-view.c			\
-	e-mail-attachment-bar.c				\
 	e-mail-autoconfig.c				\
 	e-mail-backend.c				\
 	e-mail-browser.c				\
@@ -185,10 +179,6 @@ libevolution_mail_la_SOURCES =				\
 	em-folder-tree-model.c				\
 	em-folder-tree.c				\
 	em-folder-utils.c				\
-	em-format-hook.c				\
-	em-format-html-display.c			\
-	em-format-html-print.c				\
-	em-format-html.c				\
 	em-search-context.c				\
 	em-subscription-editor.c			\
 	em-utils.c					\
diff --git a/mail/e-http-request.c b/mail/e-http-request.c
index a9415b2..95a97e6 100644
--- a/mail/e-http-request.c
+++ b/mail/e-http-request.c
@@ -26,10 +26,13 @@
 #include <webkit/webkit.h>
 
 #include <e-util/e-util.h>
+#include <mail/em-utils.h>
+#include <libemail-engine/e-mail-enumtypes.h>
 
 #include <string.h>
 
-#include "em-format-html.h"
+#include <em-format/e-mail-formatter.h>
+#include <shell/e-shell.h>
 
 #define d(x)
 
@@ -41,7 +44,7 @@ struct _EHTTPRequestPrivate {
 	gchar *content_type;
 	gint content_length;
 
-	EMFormatHTML *efh;
+	EMailPartList *parts_list;
 };
 
 G_DEFINE_TYPE (EHTTPRequest, e_http_request, SOUP_TYPE_REQUEST)
@@ -208,9 +211,12 @@ handle_http_request (GSimpleAsyncResult *res,
 	EHTTPRequest *request = E_HTTP_REQUEST (object);
 	SoupURI *soup_uri;
 	gchar *evo_uri, *uri;
+	gchar *mail_uri;
 	GInputStream *stream;
 	gboolean force_load_images = FALSE;
+	EMailImageLoadingPolicy image_policy;
 	gchar *uri_md5;
+	EMailFormatter *formatter;
 
 	const gchar *user_cache_dir;
 	CamelDataCache *cache;
@@ -222,9 +228,15 @@ handle_http_request (GSimpleAsyncResult *res,
 		return;
 	}
 
+	formatter = e_mail_formatter_new ();
+
 	/* Remove the __evo-mail query */
 	soup_uri = soup_request_get_uri (SOUP_REQUEST (request));
 	query = soup_form_decode (soup_uri->query);
+	mail_uri = g_hash_table_lookup (query, "__evo-mail");
+	if (mail_uri)
+		mail_uri = g_strdup (mail_uri);
+
 	g_hash_table_remove (query, "__evo-mail");
 
 	/* Remove __evo-load-images if present (and in such case set
@@ -306,7 +318,36 @@ handle_http_request (GSimpleAsyncResult *res,
 
 	/* Item not found in cache, but image loading policy allows us to fetch
 	 * it from the interwebs */
-	if (force_load_images || em_format_html_can_load_images (request->priv->efh)) {
+	image_policy = e_mail_formatter_get_image_loading_policy (formatter);
+	if (!force_load_images && mail_uri &&
+	    (image_policy == E_MAIL_IMAGE_LOADING_POLICY_SOMETIMES)) {
+		SoupSession *session;
+		GHashTable *parts;
+		gchar *decoded_uri;
+		EMailPartList *part_list;
+
+		session = webkit_get_default_session ();
+		parts = g_object_get_data (G_OBJECT (session), "mails");
+		decoded_uri = soup_uri_decode (mail_uri);
+
+		part_list = g_hash_table_lookup (parts, decoded_uri);
+		if (part_list) {
+			EShell *shell;
+			ESourceRegistry *registry;
+			CamelInternetAddress *addr;
+
+			shell = e_shell_get_default ();
+			registry = e_shell_get_registry (shell);
+			addr = camel_mime_message_get_from (part_list->message);
+			force_load_images = em_utils_in_addressbook (
+					registry, addr, FALSE);
+		}
+
+		g_free (decoded_uri);
+	}
+
+	if ((image_policy == E_MAIL_IMAGE_LOADING_POLICY_ALWAYS) ||
+	    force_load_images) {
 
 		SoupRequester *requester;
 		SoupRequest *http_request;
@@ -393,6 +434,8 @@ handle_http_request (GSimpleAsyncResult *res,
  cleanup:
 	g_free (uri);
 	g_free (uri_md5);
+	if (mail_uri)
+		g_free (mail_uri);
 }
 
 static void
@@ -405,9 +448,9 @@ http_request_finalize (GObject *object)
 		request->priv->content_type = NULL;
 	}
 
-	if (request->priv->efh) {
-		g_object_unref (request->priv->efh);
-		request->priv->efh = NULL;
+	if (request->priv->parts_list) {
+		g_object_unref (request->priv->parts_list);
+		request->priv->parts_list = NULL;
 	}
 
 	G_OBJECT_CLASS (e_http_request_parent_class)->finalize (object);
@@ -434,7 +477,7 @@ http_request_send_async (SoupRequest *request,
 	SoupURI *uri;
 	const gchar *enc;
 	SoupSession *session;
-	GHashTable *formatters, *query;
+	GHashTable *mails, *query;
 
 	ehr = E_HTTP_REQUEST (request);
 	uri = soup_request_get_uri (request);
@@ -452,16 +495,16 @@ http_request_send_async (SoupRequest *request,
 	mail_uri = soup_uri_decode (enc);
 
 	session = webkit_get_default_session ();
-	formatters = g_object_get_data (G_OBJECT (session), "formatters");
-	g_return_if_fail (formatters != NULL);
+	mails = g_object_get_data (G_OBJECT (session), "mails");
+	g_return_if_fail (mails != NULL);
 
-	ehr->priv->efh = g_hash_table_lookup (formatters, mail_uri);
+	ehr->priv->parts_list = g_hash_table_lookup (mails, mail_uri);
 	g_free (mail_uri);
 
-	g_return_if_fail (ehr->priv->efh);
+	g_return_if_fail (ehr->priv->parts_list);
 
 	/* Make sure the formatter lives until we are finished here */
-	g_object_ref (ehr->priv->efh);
+	g_object_ref (ehr->priv->parts_list);
 
 	simple = g_simple_async_result_new (
 		G_OBJECT (request), callback,
diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c
index 806980d..eda9d6c 100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@ -39,7 +39,6 @@
 #include "mail/e-mail-reader.h"
 #include "mail/e-mail-reader-utils.h"
 #include "mail/em-folder-tree-model.h"
-#include "mail/em-format-html-display.h"
 #include "mail/message-list.h"
 
 #define E_MAIL_BROWSER_GET_PRIVATE(obj) \
@@ -56,7 +55,7 @@ struct _EMailBrowserPrivate {
 	GtkUIManager *ui_manager;
 	EFocusTracker *focus_tracker;
 
-	EMFormatWriteMode mode;
+	EMailFormatterMode mode;
 
 	GtkWidget *main_menu;
 	GtkWidget *main_toolbar;
@@ -915,7 +914,7 @@ e_mail_browser_class_init (EMailBrowserClass *class)
 			NULL,
 			0,
 			G_MAXINT,
-			EM_FORMAT_WRITE_MODE_NORMAL,
+			E_MAIL_FORMATTER_MODE_NORMAL,
 			G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
@@ -951,7 +950,7 @@ GtkWidget *
 e_mail_browser_new (EMailBackend *backend,
                     CamelFolder *folder,
                     const gchar *msg_uid,
-                    EMFormatWriteMode mode)
+                    EMailFormatterMode mode)
 {
 	GtkWidget *widget;
 
diff --git a/mail/e-mail-browser.h b/mail/e-mail-browser.h
index 88f8174..849daeb 100644
--- a/mail/e-mail-browser.h
+++ b/mail/e-mail-browser.h
@@ -64,7 +64,7 @@ GType		e_mail_browser_get_type		(void);
 GtkWidget *	e_mail_browser_new		(EMailBackend *backend,
 						 CamelFolder *folder,
 						 const gchar *message_uid,
-						 EMFormatWriteMode mode);
+						 EMailFormatterMode mode);
 void		e_mail_browser_close		(EMailBrowser *browser);
 gboolean	e_mail_browser_get_show_deleted	(EMailBrowser *browser);
 void		e_mail_browser_set_show_deleted (EMailBrowser *browser,
diff --git a/mail/e-mail-config-lookup-page.c b/mail/e-mail-config-lookup-page.c
index 0154a05..d200c3c 100644
--- a/mail/e-mail-config-lookup-page.c
+++ b/mail/e-mail-config-lookup-page.c
@@ -29,7 +29,7 @@ G_DEFINE_TYPE_WITH_CODE (
 	EMailConfigLookupPage,
 	e_mail_config_lookup_page,
 	GTK_TYPE_BOX,
-	G_IMPLEMENT_INTERFACE(
+	G_IMPLEMENT_INTERFACE (
 		E_TYPE_MAIL_CONFIG_PAGE,
 		e_mail_config_lookup_page_interface_init))
 
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index ca807a6..4f72e84 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -28,6 +28,12 @@
 #include <glib/gi18n.h>
 #include <gdk/gdk.h>
 
+#include <em-format/e-mail-part-utils.h>
+#include <em-format/e-mail-formatter-extension.h>
+#include <em-format/e-mail-extension-registry.h>
+#include <em-format/e-mail-part-attachment.h>
+#include <em-format/e-mail-formatter-print.h>
+
 #include "e-util/e-marshal.h"
 #include "e-util/e-util.h"
 #include "e-util/e-plugin-ui.h"
@@ -37,8 +43,7 @@
 #include "mail/em-utils.h"
 #include "mail/e-mail-request.h"
 #include "mail/e-http-request.h"
-#include "mail/em-format-html-display.h"
-#include "mail/e-mail-attachment-bar.h"
+#include "widgets/misc/e-attachment-bar.h"
 #include "widgets/misc/e-attachment-button.h"
 
 #include <camel/camel.h>
@@ -54,9 +59,10 @@ G_DEFINE_TYPE (EMailDisplay, e_mail_display, E_TYPE_WEB_VIEW)
 	((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate))
 
 struct _EMailDisplayPrivate {
-	EMFormatHTML *formatter;
+	EMailPartList *part_list;
+	EMailFormatterMode mode;
+	EMailFormatter *formatter;
 
-	EMFormatWriteMode mode;
 	gboolean headers_collapsable;
 	gboolean headers_collapsed;
 
@@ -66,12 +72,14 @@ struct _EMailDisplayPrivate {
         gint force_image_load: 1;
 
 	GSettings *settings;
+
+	GHashTable *widgets;
 };
 
 enum {
 	PROP_0,
-	PROP_FORMATTER,
 	PROP_MODE,
+	PROP_PART_LIST,
 	PROP_HEADERS_COLLAPSABLE,
 	PROP_HEADERS_COLLAPSED,
 };
@@ -197,45 +205,15 @@ formatter_image_loading_policy_changed_cb (GObject *object,
 static void
 mail_display_update_formatter_colors (EMailDisplay *display)
 {
-	EMFormatHTMLColorType type;
-	EMFormatHTML *formatter;
-	GdkColor *color;
-	GtkStateType state;
 	GtkStyle *style;
-
-	state = gtk_widget_get_state (GTK_WIDGET (display));
-	formatter = display->priv->formatter;
+	GtkStateType state;
 
 	if (!display->priv->formatter)
 		return;
 
 	style = gtk_widget_get_style (GTK_WIDGET (display));
-	if (style == NULL)
-		return;
-
-	g_object_freeze_notify (G_OBJECT (formatter));
-
-	color = &style->bg[state];
-	type = EM_FORMAT_HTML_COLOR_BODY;
-	em_format_html_set_color (formatter, type, color);
-
-	color = &style->base[GTK_STATE_NORMAL];
-	type = EM_FORMAT_HTML_COLOR_CONTENT;
-	em_format_html_set_color (formatter, type, color);
-
-	color = &style->dark[state];
-	type = EM_FORMAT_HTML_COLOR_FRAME;
-	em_format_html_set_color (formatter, type, color);
-
-	color = &style->fg[state];
-	type = EM_FORMAT_HTML_COLOR_HEADER;
-	em_format_html_set_color (formatter, type, color);
-
-	color = &style->text[state];
-	type = EM_FORMAT_HTML_COLOR_TEXT;
-	em_format_html_set_color (formatter, type, color);
-
-	g_object_thaw_notify (G_OBJECT (formatter));
+	state = gtk_widget_get_state (GTK_WIDGET (display));
+	e_mail_formatter_set_style (display->priv->formatter, style, state);
 }
 
 static void
@@ -245,10 +223,10 @@ mail_display_set_property (GObject *object,
                            GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_FORMATTER:
-			e_mail_display_set_formatter (
+		case PROP_PART_LIST:
+			e_mail_display_set_parts_list (
 				E_MAIL_DISPLAY (object),
-				g_value_get_object (value));
+				g_value_get_pointer (value));
 			return;
 		case PROP_MODE:
 			e_mail_display_set_mode (
@@ -277,9 +255,9 @@ mail_display_get_property (GObject *object,
                            GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_FORMATTER:
-			g_value_set_object (
-				value, e_mail_display_get_formatter (
+		case PROP_PART_LIST:
+			g_value_set_pointer (
+				value, e_mail_display_get_parts_list (
 				E_MAIL_DISPLAY (object)));
 			return;
 		case PROP_MODE:
@@ -309,9 +287,9 @@ mail_display_dispose (GObject *object)
 
 	priv = E_MAIL_DISPLAY_GET_PRIVATE (object);
 
-	if (priv->formatter) {
-		g_object_unref (priv->formatter);
-		priv->formatter = NULL;
+	if (priv->part_list) {
+		g_object_unref (priv->part_list);
+		priv->part_list = NULL;
 	}
 
 	if (priv->settings) {
@@ -319,6 +297,11 @@ mail_display_dispose (GObject *object)
 		priv->settings = NULL;
 	}
 
+	if (priv->widgets) {
+		g_hash_table_destroy (priv->widgets);
+		priv->widgets = NULL;
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -353,18 +336,14 @@ mail_display_process_mailto (EWebView *web_view,
 	g_return_val_if_fail (mailto_uri != NULL, FALSE);
 
 	if (g_ascii_strncasecmp (mailto_uri, "mailto:";, 7) == 0) {
-		EMFormat *format;
-		CamelFolder *folder = NULL;
 		EShell *shell;
+		EMailPartList *part_list;
 
-		format = (EMFormat *) E_MAIL_DISPLAY (web_view)->priv->formatter;
-
-		if (format != NULL && format->folder != NULL)
-			folder = format->folder;
+		part_list = E_MAIL_DISPLAY (web_view)->priv->part_list;
 
 		shell = e_shell_get_default ();
 		em_utils_compose_new_message_with_mailto (
-			shell, mailto_uri, folder);
+			shell, mailto_uri, part_list->folder);
 
 		return TRUE;
 	}
@@ -380,7 +359,6 @@ mail_display_link_clicked (WebKitWebView *web_view,
                            WebKitWebPolicyDecision *policy_decision,
                            gpointer user_data)
 {
-	EMailDisplay *display;
 	const gchar *uri = webkit_network_request_get_uri (request);
 
 	if (g_str_has_prefix (uri, "file://")) {
@@ -397,10 +375,6 @@ mail_display_link_clicked (WebKitWebView *web_view,
 		g_free (filename);
 	}
 
-	display = E_MAIL_DISPLAY (web_view);
-	if (display->priv->formatter == NULL)
-		return FALSE;
-
 	if (mail_display_process_mailto (E_WEB_VIEW (web_view), uri, NULL)) {
 		/* do nothing, function handled the "mailto:"; uri already */
 		webkit_web_policy_decision_ignore (policy_decision);
@@ -457,10 +431,11 @@ mail_display_resource_requested (WebKitWebView *web_view,
                                  gpointer user_data)
 {
 	EMailDisplay *display = E_MAIL_DISPLAY (web_view);
-	EMFormat *formatter = EM_FORMAT (display->priv->formatter);
+	EMailPartList *part_list;
 	const gchar *uri = webkit_network_request_get_uri (request);
 
-	if (!formatter) {
+	part_list = display->priv->part_list;
+	if (!part_list) {
 		return;
 	}
 
@@ -468,10 +443,10 @@ mail_display_resource_requested (WebKitWebView *web_view,
 	if (g_str_has_prefix (uri, "cid:")) {
 
 		/* Always write raw content of CID object */
-		gchar *new_uri = em_format_build_mail_uri (formatter->folder,
-			formatter->message_uid,
+		gchar *new_uri = e_mail_part_build_uri (
+			part_list->folder, part_list->message_uid,
 			"part_id", G_TYPE_STRING, uri,
-			"mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW, NULL);
+			"mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, NULL);
 
 		webkit_network_request_set_uri (request, new_uri);
 
@@ -499,6 +474,7 @@ mail_display_resource_requested (WebKitWebView *web_view,
 		GHashTable *query;
 		gchar *uri_md5;
 		CamelStream *stream;
+		EMailImageLoadingPolicy image_policy;
 
                 /* Open Evolution's cache */
 		uri_md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
@@ -509,15 +485,17 @@ mail_display_resource_requested (WebKitWebView *web_view,
                 /* If the URI is not cached and we are not allowed to load it
                  * then redirect to invalid URI, so that webkit would display
                  * a native placeholder for it. */
+		image_policy = e_mail_formatter_get_image_loading_policy (
+					display->priv->formatter);
 		if (!stream && !display->priv->force_image_load &&
-		    !em_format_html_can_load_images (display->priv->formatter)) {
+		    (image_policy == E_MAIL_IMAGE_LOADING_POLICY_NEVER)) {
 			webkit_network_request_set_uri (request, "about:blank");
 			return;
 		}
 
 		new_uri = g_strconcat ("evo-", uri, NULL);
-		mail_uri = em_format_build_mail_uri (formatter->folder,
-				formatter->message_uid, NULL, NULL);
+		mail_uri = e_mail_part_build_uri (part_list->folder,
+				part_list->message_uid, NULL, NULL);
 
 		soup_uri = soup_uri_new (new_uri);
 		if (soup_uri->query) {
@@ -557,6 +535,9 @@ find_element_by_id (WebKitDOMDocument *document,
 	WebKitDOMElement *element;
 	gulong i, length;
 
+	if (!WEBKIT_DOM_IS_DOCUMENT (document))
+		return NULL;
+
         /* Try to look up the element in this DOM document */
 	element = webkit_dom_document_get_element_by_id (document, id);
 	if (element)
@@ -595,7 +576,6 @@ mail_display_plugin_widget_resize (GObject *object,
 	gint height;
 
 	widget = GTK_WIDGET (object);
-	gtk_widget_get_preferred_height (widget, &height, NULL);
 	parent_element = g_object_get_data (object, "parent_element");
 
 	if (!parent_element || !WEBKIT_DOM_IS_ELEMENT (parent_element)) {
@@ -604,6 +584,14 @@ mail_display_plugin_widget_resize (GObject *object,
 		return;
 	}
 
+	/* For attachment bar, we need to ask for height it's parent,
+	 * GtkBox, because EAttachmentBar itself lies about it's real height. */
+	if (E_IS_ATTACHMENT_BAR (widget)) {
+		widget = gtk_widget_get_parent (widget);
+	}
+
+	gtk_widget_get_preferred_height (widget, &height, NULL);
+
         /* Int -> Str */
 	dim = g_strdup_printf ("%d", height);
 
@@ -618,6 +606,31 @@ static void
 mail_display_plugin_widget_realize_cb (GtkWidget *widget,
                                        gpointer user_data)
 {
+	WebKitDOMHTMLElement *el;
+
+	if (GTK_IS_BOX (widget)) {
+		GList *children;
+
+		children = gtk_container_get_children (GTK_CONTAINER (widget));
+		if (children && children->data &&
+		    E_IS_ATTACHMENT_BAR (children->data)) {
+			widget = children->data;
+		}
+
+		g_list_free (children);
+	}
+
+	/* First check if we are actually supposed to be visible */
+	el = g_object_get_data (G_OBJECT (widget), "parent_element");
+	if (!el || !WEBKIT_DOM_IS_HTML_ELEMENT (el)) {
+		g_warning ("UAAAAA");
+	} else {
+		if (webkit_dom_html_element_get_hidden (el)) {
+			gtk_widget_hide (widget);
+			return;
+		}
+	}
+
         /* Initial resize of the <object> element when the widget
          * is displayed for the first time. */
 	mail_display_plugin_widget_resize (G_OBJECT (widget), NULL, user_data);
@@ -647,166 +660,184 @@ plugin_widget_set_parent_element (GtkWidget *widget,
          * and the GtkWidget to "widget" data of the DOM Element */
 	g_object_set_data (G_OBJECT (widget), "parent_element", element);
 	g_object_set_data (G_OBJECT (element), "widget", widget);
+
+	g_object_bind_property (
+		element, "hidden",
+		widget, "visible",
+		G_BINDING_SYNC_CREATE |
+		G_BINDING_INVERT_BOOLEAN);
 }
 
 static void
-attachment_button_expanded (GObject *object,
-                            GParamSpec *pspec,
-                            gpointer user_data)
+toggle_widget_visibility (EAttachmentButton *button,
+                          EMailDisplay *display,
+                          WebKitDOMElement *element)
 {
-	EAttachmentButton *button = E_ATTACHMENT_BUTTON (object);
-	WebKitDOMElement *attachment = user_data;
-	WebKitDOMCSSStyleDeclaration *css;
-	gboolean expanded;
+	gchar *id;
+	GtkWidget *widget;
 
-	d(printf("Attachment button %s (%p) expansion state toggled!\n",
-		(gchar *) g_object_get_data (object, "uri"), object));
+	id = webkit_dom_html_element_get_id (WEBKIT_DOM_HTML_ELEMENT (element));
+	if (!id || !*id) {
+		return;
+	}
 
-	expanded = e_attachment_button_get_expanded (button) &&
-			gtk_widget_get_visible (GTK_WIDGET (button));
+	if (!display->priv->widgets) {
+		g_free (id);
+		return;
+	}
 
-	if (!WEBKIT_DOM_IS_ELEMENT (attachment)) {
-		d(printf("%s: Parent element for button %s does not exist!\n",
-			G_STRFUNC, (gchar *) g_object_get_data (object, "uri")));
+	widget = g_hash_table_lookup (display->priv->widgets, id);
+	g_free (id);
+	if (!widget) {
 		return;
 	}
 
-        /* Show or hide the DIV which contains the attachment (iframe, image...) */
-	css = webkit_dom_element_get_style (attachment);
-	webkit_dom_css_style_declaration_set_property (
-		css, "display", expanded ? "block" : "none", "", NULL);
-}
+	/* If the widget encapsulates EAttachmentBar then check, whether
+	 * the attachment bar is not empty. We want to display it only
+	 * when there's at least one attachment */
+	if (GTK_IS_BOX (widget)) {
+		GList *children;
 
-static void
-constraint_widget_visibility (GObject *object,
-                              GParamSpec *pspec,
-                              gpointer user_data)
-{
-	GtkWidget *widget = GTK_WIDGET (object);
-	EAttachmentButton *button = user_data;
+		children = gtk_container_get_children (GTK_CONTAINER (widget));
+		if (children && children->data && E_IS_ATTACHMENT_BAR (children->data)) {
+			EAttachmentStore *store;
 
-	gboolean can_show = e_attachment_button_get_expanded (button);
-	gboolean is_visible = gtk_widget_get_visible (widget);
+			store = e_attachment_bar_get_store (
+					E_ATTACHMENT_BAR (children->data));
 
-	if (is_visible && !can_show)
-		gtk_widget_hide (widget);
-	else if (!is_visible && can_show)
-		gtk_widget_show (widget);
+			g_list_free (children);
+
+			/* Don't allow to display such attachment bar,
+			 * but always allow to hide it */
+			if (e_attachment_button_get_expanded (button) &&
+			    (e_attachment_store_get_num_attachments (store) == 0)) {
+				return;
+			}
+		}
+	}
 
-        /* Otherwise it's OK */
+	webkit_dom_html_element_set_hidden (
+		WEBKIT_DOM_HTML_ELEMENT (element),
+		!e_attachment_button_get_expanded (button));
+
+	if (e_attachment_button_get_expanded (button)) {
+		gtk_widget_show (widget);
+	} else {
+		gtk_widget_hide (widget);
+	}
 }
 
+/**
+ * @button: An #EAttachmentButton
+ * @iframe: An iframe element containing document with an attachment
+ * 	    represented by the @button
+ */
 static void
-bind_iframe_content_visibility (EAttachmentButton *button,
-                                WebKitDOMElement *iframe)
+bind_iframe_content_visibility (WebKitDOMElement *iframe,
+                                EMailDisplay *display,
+                                EAttachmentButton *button)
 {
 	WebKitDOMDocument *document;
 	WebKitDOMNodeList *nodes;
 	gulong i, length;
 
-	if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (iframe))
+	if (!iframe || !WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (iframe))
 		return;
 
 	document = webkit_dom_html_iframe_element_get_content_document (
 			WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
+	if (!WEBKIT_DOM_IS_DOCUMENT (document))
+		return;
+
 	nodes = webkit_dom_document_get_elements_by_tag_name (document, "object");
 	length = webkit_dom_node_list_get_length (nodes);
 
-	d(printf("Found %ld objects within iframe %s\n", length,
-		webkit_dom_html_iframe_element_get_name (
-			WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe))));
+	d ({
+		gchar *name = webkit_dom_html_iframe_element_get_name (
+				WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
+		printf("Found %ld objects within iframe %s\n", length, name);
+		g_free (name);
+	});
 
         /* Iterate through all <object>s and bind visibility of their widget
          * with expanded-state of related attachment button */
 	for (i = 0; i < length; i++) {
 
 		WebKitDOMNode *node = webkit_dom_node_list_item (nodes, i);
-		GtkWidget *widget;
-
-		widget = g_object_get_data (G_OBJECT (node), "widget");
-		if (!widget)
-			continue;
-
-		d(printf("Binding visibility of widget %s (%p) with button %s (%p)\n",
-			(gchar *) g_object_get_data (G_OBJECT (widget), "uri"), widget,
-			(gchar *) g_object_get_data (G_OBJECT (button), "uri"), button));
-
-		g_object_bind_property (
-			button, "expanded",
-			widget, "visible",
-			G_BINDING_SYNC_CREATE);
 
-                /* Ensure that someone won't attempt to _show() the widget when
-                 * it is supposed to be hidden and vice versa. */
-		g_signal_connect (widget, "notify::visible",
-			G_CALLBACK (constraint_widget_visibility), button);
+		/* Initial sync */
+		toggle_widget_visibility (button, display, WEBKIT_DOM_ELEMENT (node));
 	}
 }
 
 static void
-bind_attachment_iframe_visibility (GObject *object,
-                                   GParamSpec *pspec,
-                                   gpointer user_data)
+attachment_button_expanded (GObject *object,
+                            GParamSpec *pspec,
+                            gpointer user_data)
 {
-	WebKitWebFrame *webframe;
-	const gchar *frame_name;
-	gchar *button_uri;
+	EAttachmentButton *button = E_ATTACHMENT_BUTTON (object);
+	EMailDisplay *display = user_data;
 	WebKitDOMDocument *document;
-	WebKitDOMElement *attachment;
-	WebKitDOMElement *button_element;
-	WebKitDOMNodeList *nodes;
-	gulong i, length;
-	GtkWidget *button;
-
-        /* Whenever an <iframe> is loaded, bind visibility of all GtkWidgets
-         * the document within the <iframe> contains with "expanded" property
-         * of the EAttachmentButton */
+	WebKitDOMElement *element;
+	WebKitDOMCSSStyleDeclaration *css;
+	gboolean expanded;
+	gchar *id;
 
-	webframe = WEBKIT_WEB_FRAME (object);
-	if (webkit_web_frame_get_load_status (webframe) != WEBKIT_LOAD_FINISHED)
-		return;
+	d(printf("Attachment button %s has been %s!\n",
+		(gchar *) g_object_get_data (object, "uri"),
+		(e_attachment_button_get_expanded (button) ? "expanded" : "collapsed")));
 
-	frame_name = webkit_web_frame_get_name (webframe);
+	expanded = e_attachment_button_get_expanded (button) &&
+			gtk_widget_get_visible (GTK_WIDGET (button));
 
-	d(printf("Rebinding visibility of frame %s because it's URL changed\n",
-		 frame_name));
+	document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
+	element = find_element_by_id (document, g_object_get_data (object, "attachment_id"));
 
-        /* Get DOMDocument of the main document */
-	document = webkit_web_view_get_dom_document (
-		webkit_web_frame_get_web_view (webframe));
-	if (!document)
+	if (!WEBKIT_DOM_IS_ELEMENT (element)) {
+		d(printf("%s: Content <div> of attachment %s does not exist!!\n",
+			G_STRFUNC, (gchar *) g_object_get_data (object, "uri")));
 		return;
+	}
 
-        /* Find the <DIV> containing the <iframe> and related EAttachmentButton
-         * within the DOM */
-	attachment = find_element_by_id (document, frame_name);
-	if (!attachment)
-		return;
+        /* Show or hide the DIV which contains the attachment (iframe, image...) */
+	css = webkit_dom_element_get_style (element);
+	webkit_dom_css_style_declaration_set_property (
+		css, "display", expanded ? "block" : "none", "", NULL);
+
+	id = g_strconcat (g_object_get_data (object, "attachment_id"), ".iframe", NULL);
+	element = find_element_by_id (document, id);
+	g_free (id);
 
-	button_uri = g_strconcat (frame_name, ".attachment_button", NULL);
-	button_element = find_element_by_id (document, button_uri);
-	g_free (button_uri);
-	if (!button_element)
+	if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
+		d(printf("%s: No <iframe> found\n",
+			 (gchar *) g_object_get_data (object, "attachment_id")));
 		return;
+	}
+	bind_iframe_content_visibility (element, display, button);
+}
 
-	button = g_object_get_data (G_OBJECT (button_element), "widget");
+static void
+mail_display_attachment_count_changed (EAttachmentStore *store,
+                                       GParamSpec *pspec,
+                                       GtkWidget *box)
+{
+	WebKitDOMHTMLElement *element;
+	GList *children;
 
-        /* Get <iframe> representing the attachment content */
-	nodes = webkit_dom_element_get_elements_by_tag_name (attachment, "iframe");
-	length = webkit_dom_node_list_get_length (nodes);
-	for (i = 0; i < length; i++) {
+	children = gtk_container_get_children (GTK_CONTAINER (box));
+	g_return_if_fail (children  && children->data);
 
-		WebKitDOMNode *node =
-			webkit_dom_node_list_item (nodes, i);
+	element = g_object_get_data (children->data, "parent_element");
+	g_list_free (children);
 
-		if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node))
-			continue;
+	g_return_if_fail (WEBKIT_DOM_IS_HTML_ELEMENT (element));
 
-                /* Bind visibility of all GtkWidget within the
-                 * iframe with "expanded" property of the button */
-		bind_iframe_content_visibility (
-			E_ATTACHMENT_BUTTON (button),
-			WEBKIT_DOM_ELEMENT (node));
+	if (e_attachment_store_get_num_attachments (store) == 0) {
+		gtk_widget_hide (box);
+		webkit_dom_html_element_set_hidden (element, TRUE);
+	} else {
+		gtk_widget_show (box);
+		webkit_dom_html_element_set_hidden (element, FALSE);
 	}
 }
 
@@ -817,44 +848,91 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
                                       GHashTable *param,
                                       gpointer user_data)
 {
-	EMFormat *emf;
 	EMailDisplay *display;
-	EMFormatPURI *puri;
+	EMailExtensionRegistry *reg;
+	EMailFormatterExtension *extension;
+	GQueue *extensions;
+	GList *iter;
+	EMailPart *part;
 	GtkWidget *widget;
-	gchar *puri_uri;
+	gchar *part_id, *type, *object_uri;
 
-	puri_uri = g_hash_table_lookup (param, "data");
-	if (!puri_uri || !g_str_has_prefix (uri, "mail://"))
+	part_id = g_hash_table_lookup (param, "data");
+	if (!part_id || !g_str_has_prefix (uri, "mail://"))
+		return NULL;
+
+	type = g_hash_table_lookup (param, "type");
+	if (!type)
 		return NULL;
 
 	display = E_MAIL_DISPLAY (web_view);
-	emf = (EMFormat *) display->priv->formatter;
 
-	puri = em_format_find_puri (emf, puri_uri);
-	if (!puri) {
+	if ((widget = g_hash_table_lookup (display->priv->widgets, part_id)) != NULL) {
+		d(printf("Handeled %s widget request from cache\n", part_id));
+		return widget;
+	}
+
+	/* Findt EMailPart representing requested widget */
+	part = e_mail_part_list_find_part (display->priv->part_list, part_id);
+	if (!part) {
 		return NULL;
 	}
 
-	if (puri->widget_func)
-		widget = puri->widget_func (emf, puri, NULL);
-	else
-		widget = NULL;
+	reg = e_mail_formatter_get_extension_registry (display->priv->formatter);
+	extensions = e_mail_extension_registry_get_for_mime_type (reg, type);
+	if (!extensions)
+		return NULL;
+
+	extension = NULL;
+	for (iter = g_queue_peek_head_link (extensions); iter; iter = iter->next) {
+
+		extension = iter->data;
+		if (!extension)
+			continue;
 
+		if (e_mail_formatter_extension_has_widget (extension))
+			break;
+	}
+
+	if (!extension)
+		return NULL;
+
+	/* Get the widget from formatter */
+	widget = e_mail_formatter_extension_get_widget (
+			extension, display->priv->part_list, part, param);
+	d(printf("Created widget %s (%p) for part %s\n",
+			G_OBJECT_TYPE_NAME (widget), widget, part_id));
+
+	/* Should not happen! WebKit will display an ugly 'Plug-in not available'
+	 * placeholder instead of hiding the <object> element */
 	if (!widget)
 		return NULL;
 
+	/* Attachment button has URI different then the actual PURI because
+	 * that URI identifies the attachment itself */
 	if (E_IS_ATTACHMENT_BUTTON (widget)) {
-                /* Attachment button has URI different then the actual PURI because
-                 * that URI identifies the attachment itself */
-		gchar *button_uri = g_strconcat (puri_uri, ".attachment_button", NULL);
-		g_object_set_data_full (G_OBJECT (widget), "uri",
-			button_uri, (GDestroyNotify) g_free);
+		EMailPartAttachment *empa = (EMailPartAttachment *) part;
+		gchar *attachment_part_id;
+
+		if (empa->attachment_view_part_id)
+			attachment_part_id = empa->attachment_view_part_id;
+		else
+			attachment_part_id = part_id;
+
+		object_uri = g_strconcat (attachment_part_id, ".attachment_button", NULL);
+		g_object_set_data_full (G_OBJECT (widget), "attachment_id",
+			g_strdup (attachment_part_id), (GDestroyNotify) g_free);
 	} else {
-		g_object_set_data_full (G_OBJECT (widget), "uri",
-			g_strdup (puri_uri), (GDestroyNotify) g_free);
+		object_uri = g_strdup (part_id);
 	}
 
-        /* Set widget's <object> container as GObject data "parent_element" */
+	/* Store the uri as data of the widget */
+	g_object_set_data_full (G_OBJECT (widget), "uri",
+		object_uri, (GDestroyNotify) g_free);
+
+	/* Set pointer to the <object> element as GObject data "parent_element"
+	 * and set pointer to the widget as GObject data "widget" to the <object>
+	 * element */
 	plugin_widget_set_parent_element (widget, display);
 
         /* Resizing a GtkWidget requires changing size of parent
@@ -864,26 +942,32 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
 	g_signal_connect (widget, "size-allocate",
 			  G_CALLBACK (mail_display_plugin_widget_resize), display);
 
-        /* Embed the attachment bar into the GtkBox before we do anything
-         * further with the widget. */
-	if (E_IS_MAIL_ATTACHMENT_BAR (widget)) {
-
-                /* When EMailAttachmentBar is expanded/collapsed it does not
-                 * emit size-allocate signal despite it changes it's height. */
+	if (E_IS_ATTACHMENT_BAR (widget)) {
 		GtkWidget *box = NULL;
+		EAttachmentStore *store;
 
-                /* Only when packed in box, EMailAttachmentBar reports correct 
-                 * height */
-		box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-		gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
+                /* Only when packed in box (grid does not work),
+		 * EAttachmentBar reports correct height */
+		box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+		gtk_box_pack_start (GTK_BOX (box), widget, TRUE, TRUE, 0);
 
+                /* When EAttachmentBar is expanded/collapsed it does not
+                 * emit size-allocate signal despite it changes it's height. */
 		g_signal_connect (widget, "notify::expanded",
 			G_CALLBACK (mail_display_plugin_widget_resize), display);
 		g_signal_connect (widget, "notify::active-view",
 			G_CALLBACK (mail_display_plugin_widget_resize), display);
 
-                /* Show the EAttachmentBar but not the containing layout */
+		/* Always hide an attachment bar without attachments */
+		store = e_attachment_bar_get_store (E_ATTACHMENT_BAR (widget));
+		g_signal_connect (store, "notify::num-attachments",
+			G_CALLBACK (mail_display_attachment_count_changed), box);
+
 		gtk_widget_show (widget);
+		gtk_widget_show (box);
+
+		/* Initial sync */
+		mail_display_attachment_count_changed (store, NULL, box);
 
 		widget = box;
 
@@ -894,61 +978,63 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
                  * attachment button. */
 		WebKitDOMElement *attachment;
 		WebKitDOMDocument *document;
+		EMailPartAttachment *empa = (EMailPartAttachment *) part;
+		gchar *attachment_part_id;
+
+		if (empa->attachment_view_part_id)
+			attachment_part_id = empa->attachment_view_part_id;
+		else
+			attachment_part_id = part_id;
 
+		/* Find attachment-wrapper div which contains the content of the
+		 * attachment (iframe) */
 		document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
-		attachment = find_element_by_id (document, puri_uri);
+		attachment = find_element_by_id (document, attachment_part_id);
+
+		/* None found? Attachment cannot be expanded */
 		if (!attachment) {
 			e_attachment_button_set_expandable (
 				E_ATTACHMENT_BUTTON (widget), FALSE);
 		} else {
 			const CamelContentDisposition *disposition;
-			WebKitDOMNodeList *nodes;
-			gulong i, length;
-
-                        /* Show/hide the attachment when the EAttachmentButton
-                         * is expanded/collapsed or shown/hidden */
-			g_signal_connect_data (widget, "notify::expanded",
-				G_CALLBACK (attachment_button_expanded),
-				g_object_ref (attachment), (GClosureNotify) g_object_unref, 0);
-			g_signal_connect_data (widget, "notify::visible",
-				G_CALLBACK (attachment_button_expanded),
-				g_object_ref (attachment), (GClosureNotify) g_object_unref, 0);
-                        /* Initial synchronization */
-			attachment_button_expanded (G_OBJECT (widget),
-				NULL, attachment);
-
-                        /* Find all <iframes> within the attachment and bind
-                         * it's visiblity to expanded state of the attachment btn */
-			nodes = webkit_dom_element_get_elements_by_tag_name (
-					attachment, "iframe");
-			length = webkit_dom_node_list_get_length (nodes);
-			for (i = 0; i < length; i++) {
-
-				WebKitDOMNode *node =
-					webkit_dom_node_list_item (nodes, i);
-
-				if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node))
-					continue;
-
-				bind_iframe_content_visibility (
-					E_ATTACHMENT_BUTTON (widget),
-					WEBKIT_DOM_ELEMENT (node));
-			}
 
-                        /* Expand inlined attachments */
+			e_attachment_button_set_expandable (
+				E_ATTACHMENT_BUTTON (widget), TRUE);
+
+			/* Show/hide the attachment when the EAttachmentButton
+ *                       * is expanded/collapsed or shown/hidden */
+			g_signal_connect (widget, "notify::expanded",
+				G_CALLBACK (attachment_button_expanded), display);
+			g_signal_connect (widget, "notify::visible",
+				G_CALLBACK (attachment_button_expanded), display);
+
+                        /* Automatically expand attachments that have inline
+			 * disposition or the EMailParts have specific force_inline
+			 * flag set */
 			disposition =
-				camel_mime_part_get_content_disposition (puri->part);
-			if (disposition &&
-			    g_ascii_strncasecmp (
-				disposition->disposition, "inline", 6) == 0) {
+				camel_mime_part_get_content_disposition (part->part);
+			if (!part->force_collapse &&
+			    (part->force_inline ||
+			    (g_strcmp0 (empa->snoop_mime_type, "message/rfc822") == 0) ||
+			     (disposition && disposition->disposition &&
+				g_ascii_strncasecmp (
+				     disposition->disposition, "inline", 6) == 0))) {
 
 				e_attachment_button_set_expanded (
 					E_ATTACHMENT_BUTTON (widget), TRUE);
+			} else {
+				e_attachment_button_set_expanded (
+					E_ATTACHMENT_BUTTON (widget), FALSE);
+				attachment_button_expanded (
+					G_OBJECT (widget), NULL, display);
 			}
 		}
 	}
 
-	d(printf("Created widget %s (%p)\n", puri_uri, widget));
+	g_hash_table_insert (
+		display->priv->widgets,
+		g_strdup (object_uri), g_object_ref (widget));
+
 	return widget;
 }
 
@@ -1123,18 +1209,17 @@ setup_DOM_bindings (GObject *object,
 }
 
 static void
-puri_bind_dom (GObject *object,
-               GParamSpec *pspec,
-               gpointer user_data)
+mail_parts_bind_dom (GObject *object,
+                     GParamSpec *pspec,
+                     gpointer user_data)
 {
 	WebKitWebFrame *frame;
 	WebKitLoadStatus load_status;
 	WebKitWebView *web_view;
 	WebKitDOMDocument *document;
 	EMailDisplay *display;
-	GList *iter;
-	EMFormat *emf;
-	const gchar *frame_puri;
+	GSList *iter;
+	const gchar *frame_name;
 
 	frame = WEBKIT_WEB_FRAME (object);
 	load_status = webkit_web_frame_get_load_status (frame);
@@ -1142,36 +1227,40 @@ puri_bind_dom (GObject *object,
 	if (load_status != WEBKIT_LOAD_FINISHED)
 		return;
 
-	frame_puri = webkit_web_frame_get_name (frame);
 	web_view = webkit_web_frame_get_web_view (frame);
 	display = E_MAIL_DISPLAY (web_view);
-
-	emf = EM_FORMAT (display->priv->formatter);
-	if (!emf)
+	if (display->priv->part_list == NULL)
 		return;
 
-	iter = g_hash_table_lookup (
-			emf->mail_part_table,
-			webkit_web_frame_get_name (frame));
+	frame_name = webkit_web_frame_get_name (frame);
+	for (iter = display->priv->part_list->list; iter; iter = iter->next) {
+
+		EMailPart *part = iter->data;
+		if (!part)
+			continue;
 
-	document = webkit_web_view_get_dom_document (web_view);
+		if (g_strcmp0 (part->id, frame_name) == 0)
+			break;
+	}
 
+	document = webkit_web_view_get_dom_document (web_view);
 	while (iter) {
 
-		EMFormatPURI *puri = iter->data;
-
-		if (!puri)
+		EMailPart *part = iter->data;
+		if (!part) {
+			iter = iter->next;
 			continue;
+		}
 
-		/* Iterate only the PURI rendered in the frame and all it's "subPURIs" */
-		if (!g_str_has_prefix (puri->uri, frame_puri))
+		/* Iterate only the parts rendered in the frame and all it's subparts */
+		if (!g_str_has_prefix (part->id, frame_name))
 			break;
 
-		if (puri->bind_func) {
-			WebKitDOMElement *el = find_element_by_id (document, puri->uri);
+		if (part->bind_func) {
+			WebKitDOMElement *el = find_element_by_id (document, part->id);
 			if (el) {
-				d(printf("bind_func for %s\n", puri->uri));
-				puri->bind_func (el, puri);
+				d(printf("/*bind_func*/ for %s\n", part->id));
+				part->bind_func (part, el);
 			}
 		}
 
@@ -1186,15 +1275,25 @@ mail_display_frame_created (WebKitWebView *web_view,
 {
 	d(printf("Frame %s created!\n", webkit_web_frame_get_name (frame)));
 
-        /* Re-bind visibility of this newly created <iframe> with
-         * related EAttachmentButton whenever content of this <iframe> is
-         * (re)loaded */
+	/* Call bind_func of all parts written in this frame */
 	g_signal_connect (frame, "notify::load-status",
-		G_CALLBACK (bind_attachment_iframe_visibility), NULL);
+		G_CALLBACK (mail_parts_bind_dom), NULL);
+}
 
-	/* Call bind_func of all PURIs written in this frame */
-	g_signal_connect (frame, "notify::load-status",
-		G_CALLBACK (puri_bind_dom), NULL);
+static void
+mail_display_uri_changed (EMailDisplay *display,
+                          GParamSpec *pspec,
+                          gpointer dummy)
+{
+	d(printf("EMailDisplay URI changed, recreating widgets hashtable\n"));
+
+	if (display->priv->widgets)
+		g_hash_table_destroy (display->priv->widgets);
+
+	display->priv->widgets = g_hash_table_new_full (
+					g_str_hash, g_str_equal,
+					(GDestroyNotify) g_free,
+					(GDestroyNotify) g_object_unref);
 }
 
 static void
@@ -1253,12 +1352,11 @@ e_mail_display_class_init (EMailDisplayClass *class)
 
 	g_object_class_install_property (
 		object_class,
-		PROP_FORMATTER,
-		g_param_spec_object (
-			"formatter",
-			"HTML Formatter",
+		PROP_PART_LIST,
+		g_param_spec_pointer (
+			"part-list",
+			"Part List",
 			NULL,
-			EM_TYPE_FORMAT_HTML,
 			G_PARAM_READWRITE));
 
 	g_object_class_install_property (
@@ -1268,9 +1366,9 @@ e_mail_display_class_init (EMailDisplayClass *class)
 			"mode",
 			"Display Mode",
 			NULL,
-			0,
+			E_MAIL_FORMATTER_MODE_INVALID,
 			G_MAXINT,
-			EM_FORMAT_WRITE_MODE_NORMAL,
+			E_MAIL_FORMATTER_MODE_NORMAL,
 			G_PARAM_READWRITE));
 
 	g_object_class_install_property (
@@ -1305,6 +1403,10 @@ e_mail_display_init (EMailDisplay *display)
 
 	display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display);
 
+	/* Set invalid mode so that MODE property initialization is run
+	 * completely (see e_mail_display_set_mode) */
+	display->priv->mode = E_MAIL_FORMATTER_MODE_INVALID;
+	e_mail_display_set_mode (display, E_MAIL_FORMATTER_MODE_NORMAL);
 	display->priv->force_image_load = FALSE;
 	display->priv->mailto_actions = gtk_action_group_new ("mailto");
 	gtk_action_group_add_actions (display->priv->mailto_actions, mailto_entries,
@@ -1331,6 +1433,8 @@ e_mail_display_init (EMailDisplay *display)
 			  G_CALLBACK (mail_display_plugin_widget_requested), NULL);
 	g_signal_connect (display, "frame-created",
 			  G_CALLBACK (mail_display_frame_created), NULL);
+	g_signal_connect (display, "notify::uri",
+			  G_CALLBACK (mail_display_uri_changed), NULL);
 
 	display->priv->settings = g_settings_new ("org.gnome.evolution.mail");
 	g_signal_connect_swapped (
@@ -1350,7 +1454,7 @@ e_mail_display_init (EMailDisplay *display)
 		G_CALLBACK (setup_DOM_bindings), NULL);
 	main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (display));
 	g_signal_connect (main_frame, "notify::load-status",
-			  G_CALLBACK (puri_bind_dom), NULL);
+			  G_CALLBACK (mail_parts_bind_dom), NULL);
 
         /* Because we are loading from a hard-coded string, there is
          * no chance of I/O errors.  Failure here implies a malformed
@@ -1387,75 +1491,99 @@ e_mail_display_init (EMailDisplay *display)
 	}
 }
 
-EMFormatHTML *
-e_mail_display_get_formatter (EMailDisplay *display)
+EMailFormatterMode
+e_mail_display_get_mode (EMailDisplay *display)
 {
-	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display),
+			E_MAIL_FORMATTER_MODE_NORMAL);
 
-	return display->priv->formatter;
+	return display->priv->mode;
 }
 
 void
-e_mail_display_set_formatter (EMailDisplay *display,
-                              EMFormatHTML *formatter)
+e_mail_display_set_mode (EMailDisplay *display,
+                         EMailFormatterMode mode)
 {
+	EMailFormatter *formatter;
 	g_return_if_fail (E_IS_MAIL_DISPLAY (display));
 
-	if (formatter) {
-		g_return_if_fail (EM_IS_FORMAT_HTML (formatter));
-		g_object_ref (formatter);
-	}
-
-	if (display->priv->formatter != NULL) {
-		/* The formatter might still exist after unrefing it, so 
-		 * we need to stop listening to it's request for redrawing */
-		g_signal_handlers_disconnect_by_func (
-			display->priv->formatter, e_mail_display_reload, display);
-		g_object_unref (display->priv->formatter);
-	}
+	if (display->priv->mode == mode)
+		return;
 
-	display->priv->formatter = formatter;
+	display->priv->mode = mode;
 
-	if (!formatter) {
-		e_web_view_clear (E_WEB_VIEW (display));
-		return;
+	if (display->priv->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
+		formatter = e_mail_formatter_print_new ();
+	} else {
+		formatter = e_mail_formatter_new ();
 	}
 
+	g_clear_object (&display->priv->formatter);
+	display->priv->formatter = formatter;
 	mail_display_update_formatter_colors (display);
 
 	g_signal_connect (formatter, "notify::image-loading-policy",
 		G_CALLBACK (formatter_image_loading_policy_changed_cb), display);
-	g_signal_connect_swapped (formatter, "redraw-requested",
-		G_CALLBACK (e_mail_display_reload), display);
-	g_signal_connect_swapped (formatter, "notify::charset",
-		G_CALLBACK (e_mail_display_reload), display);
 
-	g_object_notify (G_OBJECT (display), "formatter");
+	g_object_connect (formatter,
+		"swapped-signal::notify::charset",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::image-loading-policy",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::mark-citations",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::only-local-photos",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::show-sender-photo",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::show-real-date",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::animate-images",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::text-color",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::body-color",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::citation-color",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::content-color",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::frame-color",
+			G_CALLBACK (e_mail_display_reload), display,
+		"swapped-signal::notify::header-color",
+			G_CALLBACK (e_mail_display_reload), display,
+		NULL);
+
+	e_mail_display_reload (display);
+
+	g_object_notify (G_OBJECT (display), "mode");
 }
 
-EMFormatWriteMode
-e_mail_display_get_mode (EMailDisplay *display)
+EMailPartList *
+e_mail_display_get_parts_list (EMailDisplay *display)
 {
-	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display),
-			EM_FORMAT_WRITE_MODE_NORMAL);
+	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
 
-	return display->priv->mode;
+	return display->priv->part_list;
 }
 
 void
-e_mail_display_set_mode (EMailDisplay *display,
-                         EMFormatWriteMode mode)
+e_mail_display_set_parts_list (EMailDisplay *display,
+                               EMailPartList *part_list)
 {
 	g_return_if_fail (E_IS_MAIL_DISPLAY (display));
 
-	if (display->priv->mode == mode)
-		return;
+	if (part_list) {
+		g_return_if_fail (E_IS_MAIL_PART_LIST (part_list));
+		g_object_ref (part_list);
+	}
 
-	display->priv->mode = mode;
+	if (display->priv->part_list)
+		g_object_unref (display->priv->part_list);
 
-	e_mail_display_reload (display);
+	display->priv->part_list = part_list;
 
-	g_object_notify (G_OBJECT (display), "mode");
+	g_object_notify (G_OBJECT (display), "part-list");
 }
 
 gboolean
@@ -1510,16 +1638,21 @@ void
 e_mail_display_load (EMailDisplay *display,
                      const gchar *msg_uri)
 {
-	EMFormat *emf;
 	gchar *uri;
+	EMailPartList *part_list;
 
 	g_return_if_fail (E_IS_MAIL_DISPLAY (display));
 
 	display->priv->force_image_load = FALSE;
 
-	emf = EM_FORMAT (display->priv->formatter);
+	part_list = display->priv->part_list;
+	if (!part_list) {
+		e_web_view_clear (E_WEB_VIEW (display));
+		return;
+	}
 
-	uri = em_format_build_mail_uri (emf->folder, emf->message_uid,
+	uri = e_mail_part_build_uri (
+		part_list->folder, part_list->message_uid,
 		"mode", G_TYPE_INT, display->priv->mode,
 		"headers_collapsable", G_TYPE_BOOLEAN, display->priv->headers_collapsable,
 		"headers_collapsed", G_TYPE_BOOLEAN, display->priv->headers_collapsed,
diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h
index 9865a3e..e198956 100644
--- a/mail/e-mail-display.h
+++ b/mail/e-mail-display.h
@@ -24,7 +24,8 @@
 
 #include <misc/e-web-view.h>
 #include <misc/e-search-bar.h>
-#include "em-format-html.h"
+
+#include <em-format/e-mail-formatter.h>
 
 /* Standard GObject macros */
 #define E_TYPE_MAIL_DISPLAY \
@@ -62,13 +63,16 @@ struct _EMailDisplayClass {
 };
 
 GType			e_mail_display_get_type		(void);
-EMFormatHTML *		e_mail_display_get_formatter	(EMailDisplay *display);
-void			e_mail_display_set_formatter	(EMailDisplay *display,
-							 EMFormatHTML *formatter);
 
 void			e_mail_display_set_mode		(EMailDisplay *display,
-							 EMFormatWriteMode mode);
-EMFormatWriteMode	e_mail_display_get_mode		(EMailDisplay *display);
+							 EMailFormatterMode mode);
+EMailFormatterMode	e_mail_display_get_mode		(EMailDisplay *display);
+
+EMailPartList *		e_mail_display_get_parts_list	(EMailDisplay *display);
+
+void			e_mail_display_set_parts_list	(EMailDisplay *display,
+							 EMailPartList *parts_list);
+
 void			e_mail_display_set_headers_collapsable
 							(EMailDisplay *display,
 							 gboolean collapsable);
diff --git a/mail/e-mail-folder-pane.c b/mail/e-mail-folder-pane.c
index 03168ce..e6c0e92 100644
--- a/mail/e-mail-folder-pane.c
+++ b/mail/e-mail-folder-pane.c
@@ -43,7 +43,6 @@
 #include "mail/e-mail-reader.h"
 #include "mail/e-mail-reader-utils.h"
 #include "mail/em-folder-tree-model.h"
-#include "mail/em-format-html-display.h"
 #include "mail/em-composer-utils.h"
 #include "mail/em-utils.h"
 #include "mail/message-list.h"
diff --git a/mail/e-mail-paned-view.h b/mail/e-mail-paned-view.h
index 5e6879a..dbea57b 100644
--- a/mail/e-mail-paned-view.h
+++ b/mail/e-mail-paned-view.h
@@ -28,8 +28,6 @@
 #include <shell/e-shell-searchbar.h>
 #include <shell/e-shell-view.h>
 
-#include <mail/em-format-html-display.h>
-
 /* Standard GObject macros */
 #define E_TYPE_MAIL_PANED_VIEW \
 	(e_mail_paned_view_get_type ())
diff --git a/mail/e-mail-printer.c b/mail/e-mail-printer.c
index 0a52a0a..f90414f 100644
--- a/mail/e-mail-printer.c
+++ b/mail/e-mail-printer.c
@@ -24,13 +24,15 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
+#include <em-format/e-mail-formatter-print.h>
+#include <em-format/e-mail-part-utils.h>
+
 #include <e-util/e-print.h>
 #include <e-util/e-marshal.h>
 
 #include <webkit/webkitdom.h>
 
 #include "e-mail-printer.h"
-#include "em-format-html-print.h"
 #include "e-mail-display.h"
 
 static gpointer parent_class = NULL;
@@ -48,9 +50,11 @@ enum {
 #define w(x)
 
 struct _EMailPrinterPrivate {
-	EMFormatHTMLPrint *efhp;
+	EMailFormatterPrint *formatter;
+	EMailPartList *parts_list;
 
         gboolean export_mode;
+	gchar *export_filename;
 
 	GtkListStore *headers;
 
@@ -69,7 +73,7 @@ G_DEFINE_TYPE (
 
 enum {
 	PROP_0,
-	PROP_PRINT_FORMATTER
+	PROP_PART_LIST
 };
 
 enum {
@@ -88,8 +92,8 @@ enum {
 static guint signals[LAST_SIGNAL];
 
 static gint
-emp_header_name_equal (const EMFormatHeader *h1,
-                       const EMFormatHeader *h2)
+emp_header_name_equal (const EMailFormatterHeader *h1,
+                       const EMailFormatterHeader *h2)
 {
 	if ((h2->value == NULL) || (h1->value == NULL)) {
 		return g_strcmp0 (h1->name, h2->name);
@@ -169,8 +173,7 @@ emp_start_printing (GObject *object,
 
 	if (emp->priv->export_mode) {
 		gtk_print_operation_set_export_filename (
-			emp->priv->operation,
-			emp->priv->efhp->export_filename);
+			emp->priv->operation, emp->priv->export_filename);
 		webkit_web_frame_print_full (
 			frame, emp->priv->operation,
 			GTK_PRINT_OPERATION_ACTION_EXPORT, NULL);
@@ -185,32 +188,23 @@ emp_start_printing (GObject *object,
 static void
 emp_run_print_operation (EMailPrinter *emp)
 {
-	EMFormat *emf;
-	SoupSession *session;
-	GHashTable *formatters;
 	gchar *mail_uri;
 
-	emf = EM_FORMAT (emp->priv->efhp);
-	mail_uri = em_format_build_mail_uri (emf->folder, emf->message_uid, NULL, NULL);
-
-	/* It's safe to assume that session exists and contains formatters table,
-	 * because at least the message we are about to print now must be already
-	 * there */
-	session = webkit_get_default_session ();
-	formatters = g_object_get_data (G_OBJECT (session), "formatters");
-	g_hash_table_insert (formatters, g_strdup (mail_uri), emp->priv->efhp);
+	mail_uri = e_mail_part_build_uri (emp->priv->parts_list->folder,
+		emp->priv->parts_list->message_uid,
+		"__evo-load-image", G_TYPE_BOOLEAN, TRUE,
+		"mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_PRINTING,
+		NULL);
 
 	/* Print_layout is a special EMPart created by EMFormatHTMLPrint */
-	if (emp->priv->uri)
-		g_free (emp->priv->uri);
-
-	emp->priv->uri = g_strconcat (mail_uri, "?part_id=print_layout&__evo-load-images=1", NULL);
-
 	if (emp->priv->webview == NULL) {
-		emp->priv->webview = g_object_new (E_TYPE_MAIL_DISPLAY, NULL);
+		emp->priv->webview = g_object_new (
+			E_TYPE_MAIL_DISPLAY,
+			"mode", E_MAIL_FORMATTER_MODE_PRINTING, NULL);
 		e_web_view_set_enable_frame_flattening (E_WEB_VIEW (emp->priv->webview), FALSE);
 		e_mail_display_set_force_load_images (
-				E_MAIL_DISPLAY (emp->priv->webview), TRUE);
+			E_MAIL_DISPLAY (emp->priv->webview), TRUE);
+
 		g_object_ref_sink (emp->priv->webview);
 		g_signal_connect (emp->priv->webview, "notify::load-status",
 			G_CALLBACK (emp_start_printing), emp);
@@ -224,18 +218,16 @@ emp_run_print_operation (EMailPrinter *emp)
 			gtk_widget_show_all (window);
 		});
 	}
-
-	e_mail_display_set_formatter (E_MAIL_DISPLAY (emp->priv->webview),
-				      (EMFormatHTML *) emp->priv->efhp);
-
-	webkit_web_view_load_uri (emp->priv->webview, emp->priv->uri);
+	e_mail_display_set_parts_list (
+		E_MAIL_DISPLAY (emp->priv->webview), emp->priv->parts_list);
+	webkit_web_view_load_uri (emp->priv->webview, mail_uri);
 
 	g_free (mail_uri);
 }
 
 static void
 set_header_visible (EMailPrinter *emp,
-                    EMFormatHeader *header,
+                    EMailFormatterHeader *header,
                     gint index,
                     gboolean visible)
 {
@@ -263,7 +255,7 @@ header_active_renderer_toggled_cb (GtkCellRendererToggle *renderer,
 	GtkTreeIter iter;
 	GtkTreePath *p;
 	gboolean active;
-	EMFormatHeader *header;
+	EMailFormatterHeader *header;
 	gint *indices;
 
 	gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (emp->priv->headers),
@@ -301,7 +293,7 @@ emp_headers_tab_toggle_selection (GtkWidget *button,
 		return;
 
 	do {
-		EMFormatHeader *header;
+		EMailFormatterHeader *header;
 		GtkTreePath *path;
 		gint *indices;
 
@@ -594,47 +586,44 @@ emp_create_headers_tab (GtkPrintOperation *operation,
 }
 
 static void
-emp_set_formatter (EMailPrinter *emp,
-                   EMFormatHTMLPrint *formatter)
+emp_set_parts_list (EMailPrinter *emp,
+                    EMailPartList *parts_list)
 {
-	EMFormat *emf = (EMFormat *) formatter;
 	CamelMediumHeader *header;
 	GArray *headers;
 	gint i;
 	GtkTreeIter last_known;
 
-	g_return_if_fail (EM_IS_FORMAT_HTML_PRINT (formatter));
-
-	g_object_ref (formatter);
+	g_return_if_fail (parts_list);
 
-	if (emp->priv->efhp)
-		g_object_unref (emp->priv->efhp);
-
-	emp->priv->efhp = formatter;
+	emp->priv->parts_list = g_object_ref (parts_list);
 
 	if (emp->priv->headers)
 		g_object_unref (emp->priv->headers);
 	emp->priv->headers = gtk_list_store_new (5,
 		G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
 
-	headers = camel_medium_get_headers (CAMEL_MEDIUM (emf->message));
+	headers = camel_medium_get_headers (CAMEL_MEDIUM (parts_list->message));
 	if (!headers)
 		return;
 
 	for (i = 0; i < headers->len; i++) {
 		GtkTreeIter iter;
 		GList *found_header;
-		EMFormatHeader *emfh;
+		EMailFormatterHeader *emfh;
 
 		header = &g_array_index (headers, CamelMediumHeader, i);
-		emfh = em_format_header_new (header->name, header->value);
+		emfh = e_mail_formatter_header_new (header->name, header->value);
 
-		found_header = g_queue_find_custom (&EM_FORMAT (formatter)->header_list,
+		found_header = g_queue_find_custom (
+				(GQueue *) e_mail_formatter_get_headers (
+					E_MAIL_FORMATTER (emp->priv->formatter)),
 				emfh, (GCompareFunc) emp_header_name_equal);
 
 		if (!found_header) {
-			emfh->flags |= EM_FORMAT_HTML_HEADER_HIDDEN;
-			em_format_add_header_struct (EM_FORMAT (formatter), emfh);
+			emfh->flags |= E_MAIL_FORMATTER_HEADER_FLAG_HIDDEN;
+			e_mail_formatter_add_header_struct (
+				E_MAIL_FORMATTER (emp->priv->formatter), emfh);
 			gtk_list_store_append (emp->priv->headers, &iter);
 		} else {
 			if (gtk_list_store_iter_is_valid (emp->priv->headers, &last_known))
@@ -652,7 +641,7 @@ emp_set_formatter (EMailPrinter *emp,
 			COLUMN_HEADER_STRUCT, emfh, -1);
 	}
 
-	camel_medium_free_headers (CAMEL_MEDIUM (emf->message), headers);
+	camel_medium_free_headers (CAMEL_MEDIUM (parts_list->message), headers);
 }
 
 static void
@@ -665,8 +654,8 @@ emp_set_property (GObject *object,
 
 	switch (property_id) {
 
-		case PROP_PRINT_FORMATTER:
-			emp_set_formatter (emp, g_value_get_object (value));
+		case PROP_PART_LIST:
+			emp_set_parts_list (emp, g_value_get_pointer (value));
 			return;
 	}
 
@@ -683,9 +672,9 @@ emp_get_property (GObject *object,
 
 	switch (property_id) {
 
-		case PROP_PRINT_FORMATTER:
-			g_value_set_object (value,
-				e_mail_printer_get_print_formatter (emp));
+		case PROP_PART_LIST:
+			g_value_set_pointer (value,
+				emp->priv->parts_list);
 			return;
 	}
 
@@ -697,9 +686,9 @@ emp_finalize (GObject *object)
 {
 	EMailPrinterPrivate *priv = E_MAIL_PRINTER (object)->priv;
 
-	if (priv->efhp) {
-		g_object_unref (priv->efhp);
-		priv->efhp = NULL;
+	if (priv->formatter) {
+		g_object_unref (priv->formatter);
+		priv->formatter = NULL;
 	}
 
 	if (priv->headers) {
@@ -707,10 +696,10 @@ emp_finalize (GObject *object)
 
 		if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->headers), &iter)) {
 			do {
-				EMFormatHeader *header = NULL;
+				EMailFormatterHeader *header = NULL;
 				gtk_tree_model_get (GTK_TREE_MODEL (priv->headers), &iter,
 					COLUMN_HEADER_STRUCT, &header, -1);
-				em_format_header_free (header);
+				e_mail_formatter_header_free (header);
 			} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->headers), &iter));
 		}
 		g_object_unref (priv->headers);
@@ -732,6 +721,11 @@ emp_finalize (GObject *object)
 		priv->operation = NULL;
 	}
 
+	if (priv->parts_list) {
+		g_object_unref (priv->parts_list);
+		priv->parts_list = NULL;
+	}
+
         /* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -751,13 +745,13 @@ e_mail_printer_class_init (EMailPrinterClass *klass)
 
 	g_object_class_install_property (
 		object_class,
-		PROP_PRINT_FORMATTER,
-		g_param_spec_object (
-			"print-formatter",
-			NULL,
+		PROP_PART_LIST,
+		g_param_spec_pointer (
+			"parts-list",
+			"Parts List",
 			NULL,
-			EM_TYPE_FORMAT_HTML_PRINT,
-			G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY));
 
 	signals[SIGNAL_DONE] =	g_signal_new ("done",
 		G_TYPE_FROM_CLASS (klass),
@@ -775,23 +769,18 @@ e_mail_printer_init (EMailPrinter *emp)
 	emp->priv = G_TYPE_INSTANCE_GET_PRIVATE (
 		emp, E_TYPE_MAIL_PRINTER, EMailPrinterPrivate);
 
-	emp->priv->efhp = NULL;
+	emp->priv->formatter = (EMailFormatterPrint *) e_mail_formatter_print_new ();
 	emp->priv->headers = NULL;
 	emp->priv->webview = NULL;
 }
 
 EMailPrinter *
-e_mail_printer_new (EMFormatHTML *source)
+e_mail_printer_new (EMailPartList *source)
 {
 	EMailPrinter *emp;
-	EMFormatHTMLPrint *efhp;
-
-	efhp = em_format_html_print_new (source);
 
 	emp = g_object_new (E_TYPE_MAIL_PRINTER,
-		"print-formatter", efhp, NULL);
-
-	g_object_unref (efhp);
+		"parts-list", source, NULL);
 
 	return emp;
 }
@@ -830,10 +819,7 @@ e_mail_printer_get_export_filename (EMailPrinter *printer)
 {
 	g_return_val_if_fail (E_IS_MAIL_PRINTER (printer), NULL);
 
-	if (!printer->priv->efhp)
-	  return NULL;
-
-	return printer->priv->efhp->export_filename;
+	return printer->priv->export_filename;
 }
 
 void
@@ -841,19 +827,9 @@ e_mail_printer_set_export_filename (EMailPrinter *printer,
                                     const gchar *filename)
 {
 	g_return_if_fail (E_IS_MAIL_PRINTER (printer));
-	g_return_if_fail (printer->priv->efhp != NULL);
 
-	if (printer->priv->efhp->export_filename && *printer->priv->efhp->export_filename)
-	  g_free (printer->priv->efhp->export_filename);
+	if (printer->priv->export_filename)
+	  g_free (printer->priv->export_filename);
 
-	printer->priv->efhp->export_filename = g_strdup (filename);
+	printer->priv->export_filename = g_strdup (filename);
 }
-
-EMFormatHTMLPrint *
-e_mail_printer_get_print_formatter (EMailPrinter *emp)
-{
-	g_return_val_if_fail (E_IS_MAIL_PRINTER (emp), NULL);
-
-	return emp->priv->efhp;
-}
-
diff --git a/mail/e-mail-printer.h b/mail/e-mail-printer.h
index fcd163e..a0721ea 100644
--- a/mail/e-mail-printer.h
+++ b/mail/e-mail-printer.h
@@ -20,7 +20,7 @@
 #ifndef E_MAIL_PRINTER_H
 #define E_MAIL_PRINTER_H
 
-#include "mail/em-format-html-print.h"
+#include <em-format/e-mail-part-list.h>
 
 /* Standard GObject macros */
 #define E_TYPE_MAIL_PRINTER \
@@ -63,7 +63,7 @@ struct _EMailPrinterClass {
 
 GType		e_mail_printer_get_type	(void);
 
-EMailPrinter *  e_mail_printer_new	(EMFormatHTML *source);
+EMailPrinter *  e_mail_printer_new	(EMailPartList *source);
 
 void		e_mail_printer_print	(EMailPrinter *printer,
 					 gboolean export,
@@ -76,10 +76,6 @@ void            e_mail_printer_set_export_filename
 const gchar *    e_mail_printer_get_export_filename
                                         (EMailPrinter *printer);
 
-EMFormatHTMLPrint *
-		e_mail_printer_get_print_formatter
-					(EMailPrinter *printer);
-
 G_END_DECLS
 
 #endif /* E_MAIL_PRINTER_H */
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index 2240523..f56b094 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -46,13 +46,20 @@
 #include "mail/e-mail-backend.h"
 #include "mail/e-mail-browser.h"
 #include "mail/e-mail-printer.h"
+#include "mail/e-mail-display.h"
 #include "mail/em-composer-utils.h"
-#include "mail/em-format-html-print.h"
 #include "mail/em-utils.h"
 #include "mail/mail-autofilter.h"
 #include "mail/mail-vfolder-ui.h"
 #include "mail/message-list.h"
 
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+
+#define d(x)
+
+static GHashTable * mail_reader_get_mail_register (void);
+
 typedef struct _AsyncContext AsyncContext;
 
 struct _AsyncContext {
@@ -434,7 +441,7 @@ e_mail_reader_open_selected (EMailReader *reader)
 		MessageList *ml;
 
 		browser = e_mail_browser_new (backend, folder, uid,
-				EM_FORMAT_WRITE_MODE_NORMAL);
+				E_MAIL_FORMATTER_MODE_NORMAL);
 
 		e_mail_reader_set_folder (E_MAIL_READER (browser), folder);
 		e_mail_reader_set_message (E_MAIL_READER (browser), uid);
@@ -508,30 +515,109 @@ printing_done_cb (EMailPrinter *printer,
 		(GSourceFunc) destroy_printing_activity, activity, NULL);
 }
 
-void
-e_mail_reader_print (EMailReader *reader,
-                     GtkPrintOperationAction action)
-{
-	EMailDisplay *display;
-	EMailPrinter *printer;
-	EMFormatHTML *formatter;
+struct _MessagePrintingContext {
+	EMailReader *reader;
+	CamelFolder *folder;
+	gchar *message_uid;
+
 	EActivity *activity;
-	GCancellable *cancellable;
+};
 
-	g_return_if_fail (E_IS_MAIL_READER (reader));
+static void
+free_message_printing_context (struct _MessagePrintingContext *context)
+{
+	g_return_if_fail (context != NULL);
 
-	display = e_mail_reader_get_mail_display (reader);
-	formatter = e_mail_display_get_formatter (display);
+	g_clear_object (&context->reader);
+	g_clear_object (&context->folder);
+	g_clear_object (&context->activity);
 
-	activity = e_mail_reader_new_activity (reader);
+	if (context->message_uid)
+		g_free (context->message_uid);
+
+	g_free (context);
+}
+
+static void
+mail_reader_do_print_message (EMailPartList *part_list,
+                              gpointer user_data)
+{
+	EActivity *activity;
+	GCancellable *cancellable;
+	EMailPrinter *printer;
+	struct _MessagePrintingContext *context = user_data;
+
+	activity = e_mail_reader_new_activity (context->reader);
 	e_activity_set_text (activity, _("Printing"));
 	e_activity_set_state (activity, E_ACTIVITY_RUNNING);
 	cancellable = e_activity_get_cancellable (activity);
 
-	printer = e_mail_printer_new (formatter);
+	printer = e_mail_printer_new (part_list);
 	g_signal_connect (printer, "done",
 		G_CALLBACK (printing_done_cb), activity);
 	e_mail_printer_print (printer, FALSE, cancellable);
+
+	free_message_printing_context (context);
+}
+
+static void
+mail_reader_get_message_to_print_ready_cb (GObject *object,
+                                           GAsyncResult *result,
+                                           gpointer user_data)
+{
+	CamelMimeMessage *message;
+	struct _MessagePrintingContext *context = user_data;
+
+	message = camel_folder_get_message_finish (CAMEL_FOLDER (object), result, NULL);
+	if (!CAMEL_IS_MIME_MESSAGE (message)) {
+		free_message_printing_context (context);
+		return;
+	}
+
+	/* "Retrieving message" activity (or NULL) */
+	g_clear_object (&context->activity);
+
+	e_mail_reader_parse_message (
+		context->reader, context->folder, context->message_uid,
+		message, (GFunc) mail_reader_do_print_message, context);
+}
+
+void
+e_mail_reader_print (EMailReader *reader,
+                     GtkPrintOperationAction action)
+{
+	EMailPartList *parts;
+	struct _MessagePrintingContext *context;
+	MessageList *message_list;
+	gchar *uri;
+
+	context = g_new0 (struct _MessagePrintingContext, 1);
+
+	message_list = MESSAGE_LIST (e_mail_reader_get_message_list (reader));
+	context->reader = g_object_ref (reader);
+	context->message_uid = g_strdup (message_list->cursor_uid);
+	context->folder = g_object_ref (e_mail_reader_get_folder (reader));
+
+	g_return_if_fail (E_IS_MAIL_READER (reader));
+
+	uri = e_mail_part_build_uri (
+		context->folder, context->message_uid, NULL, NULL);
+	parts = e_mail_reader_lookup_part_list (reader, uri);
+	if (!parts) {
+		GCancellable *cancellable;
+
+		context->activity = e_mail_reader_new_activity (reader);
+		cancellable = e_activity_get_cancellable (context->activity);
+
+		camel_folder_get_message (
+			context->folder, context->message_uid,
+			G_PRIORITY_DEFAULT, cancellable,
+			(GAsyncReadyCallback) mail_reader_get_message_to_print_ready_cb,
+			context);
+
+	} else {
+		mail_reader_do_print_message (parts, context);
+	}
 }
 
 static void
@@ -770,15 +856,31 @@ html_contains_nonwhitespace (const gchar *html,
 }
 
 static void
+mail_reader_reply_message_parsed (EMailPartList *part_list,
+                                  gpointer user_data)
+{
+	EShell *shell;
+	EMailBackend *backend;
+	AsyncContext *context = user_data;
+
+	backend = e_mail_reader_get_backend (context->reader);
+	shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
+
+	em_utils_reply_to_message (
+		shell, part_list->message,
+		context->folder, context->message_uid,
+		context->reply_type, context->reply_style,
+		part_list, context->address);
+
+	async_context_free (context);
+}
+
+static void
 mail_reader_get_message_ready_cb (CamelFolder *folder,
                                   GAsyncResult *result,
                                   AsyncContext *context)
 {
-	EShell *shell;
-	EMailBackend *backend;
 	EAlertSink *alert_sink;
-	EMFormatHTML *formatter;
-	EMailDisplay *display;
 	CamelMimeMessage *message;
 	GError *error = NULL;
 
@@ -804,22 +906,10 @@ mail_reader_get_message_ready_cb (CamelFolder *folder,
 
 	g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
 
-	backend = e_mail_reader_get_backend (context->reader);
-	shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
-	display = e_mail_reader_get_mail_display (context->reader);
-	formatter = e_mail_display_get_formatter (display);
-
-	em_utils_reply_to_message (
-		shell, message,
-		context->folder, context->message_uid,
-		context->reply_type, context->reply_style,
-		EM_FORMAT (formatter), context->address);
-
-	g_object_unref (message);
-
-	e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED);
-
-	async_context_free (context);
+	e_mail_reader_parse_message (context->reader, context->folder,
+		context->message_uid, message,
+		(GFunc) mail_reader_reply_message_parsed,
+		context);
 }
 
 void
@@ -831,7 +921,7 @@ e_mail_reader_reply_to_message (EMailReader *reader,
 	EMailBackend *backend;
 	EShellBackend *shell_backend;
 	EMailDisplay *display;
-	EMFormatHTML *formatter;
+	EMailPartList *part_list;
 	GtkWidget *message_list;
 	CamelMimeMessage *new_message;
 	CamelInternetAddress *address = NULL;
@@ -842,6 +932,8 @@ e_mail_reader_reply_to_message (EMailReader *reader,
 	const gchar *uid;
 	gchar *selection = NULL;
 	gint length;
+	gchar *mail_uri;
+	GHashTable *mail_register;
 
 	/* This handles quoting only selected text in the reply.  If
 	 * nothing is selected or only whitespace is selected, fall
@@ -852,7 +944,6 @@ e_mail_reader_reply_to_message (EMailReader *reader,
 	backend = e_mail_reader_get_backend (reader);
 	folder = e_mail_reader_get_folder (reader);
 	display = e_mail_reader_get_mail_display (reader);
-	formatter = e_mail_display_get_formatter (display);
 	message_list = e_mail_reader_get_message_list (reader);
 	reply_style = e_mail_reader_get_reply_style (reader);
 
@@ -889,11 +980,19 @@ e_mail_reader_reply_to_message (EMailReader *reader,
 	uid = MESSAGE_LIST (message_list)->cursor_uid;
 	g_return_if_fail (uid != NULL);
 
-	if (!gtk_widget_get_mapped (GTK_WIDGET (web_view)))
+	if (!gtk_widget_get_visible (GTK_WIDGET (web_view)))
+		goto whole_message;
+
+	mail_register = mail_reader_get_mail_register ();
+	mail_uri = e_mail_part_build_uri (folder, uid, NULL, NULL);
+	part_list = g_hash_table_lookup (mail_register, mail_uri);
+	g_free (mail_uri);
+
+	if (!part_list)
 		goto whole_message;
 
 	if (src_message == NULL) {
-		src_message = EM_FORMAT (formatter)->message;
+		src_message = part_list->message;
 		if (src_message != NULL)
 			g_object_ref (src_message);
 
@@ -976,7 +1075,7 @@ whole_message:
 
 	em_utils_reply_to_message (
 		shell, src_message, folder, uid,
-		reply_type, reply_style, EM_FORMAT (formatter), address);
+		reply_type, reply_style, part_list, address);
 
 	if (address)
 		g_object_unref (address);
@@ -1419,43 +1518,58 @@ e_mail_reader_header_free (EMailReaderHeader *header)
 	g_free (header);
 }
 
+struct headers_changed_closure {
+	EMailFormatter *formatter;
+	EMailDisplay *display;
+};
+
+static void
+free_headers_changed_closure (struct headers_changed_closure *closure)
+{
+	g_clear_object (&closure->formatter);
+	g_clear_object (&closure->display);
+
+	g_free (closure);
+}
+
 static void
 headers_changed_cb (GConfClient *client,
                     guint cnxn_id,
                     GConfEntry *entry,
-                    EMFormat *emf)
+                    struct headers_changed_closure *closure)
 {
 	GSList *header_config_list, *p;
 
 	g_return_if_fail (client != NULL);
-	g_return_if_fail (EM_IS_FORMAT (emf));
 
 	header_config_list = gconf_client_get_list (
 		client, "/apps/evolution/mail/display/headers",
 		GCONF_VALUE_STRING, NULL);
 
-	em_format_clear_headers (emf);
+	e_mail_formatter_clear_headers (closure->formatter);
 	for (p = header_config_list; p; p = g_slist_next (p)) {
 		EMailReaderHeader *h;
 		gchar *xml = (gchar *) p->data;
 
 		h = e_mail_reader_header_from_xml (xml);
 		if (h && h->enabled)
-			em_format_add_header (
-				emf, h->name, NULL, EM_FORMAT_HEADER_BOLD);
+			e_mail_formatter_add_header (
+				closure->formatter, h->name, NULL,
+				E_MAIL_FORMATTER_HEADER_FLAG_BOLD);
 
 		e_mail_reader_header_free (h);
 	}
 
 	if (!header_config_list)
-		em_format_default_headers (emf);
+		e_mail_formatter_set_default_headers (closure->formatter);
 
 	g_slist_foreach (header_config_list, (GFunc) g_free, NULL);
 	g_slist_free (header_config_list);
 
 	/* force a redraw */
-	if (emf->message)
-		em_format_redraw (emf);
+	if (closure->display) {
+		e_mail_display_reload (closure->display);
+	}
 }
 
 static void
@@ -1482,26 +1596,159 @@ remove_header_notify_cb (gpointer data)
  **/
 void
 e_mail_reader_connect_headers (EMailReader *reader,
-                               EMFormat *emf)
+                               EMailFormatter *formatter)
 {
 	GConfClient *client;
 	guint notify_id;
+	struct headers_changed_closure *closure;
 
 	client = gconf_client_get_default ();
 
+	closure = g_new0 (struct headers_changed_closure, 1);
+	closure->display = g_object_ref (e_mail_reader_get_mail_display (reader));
+	closure->formatter = g_object_ref (formatter);
+
 	gconf_client_add_dir (
 		client, "/apps/evolution/mail/display",
 		GCONF_CLIENT_PRELOAD_NONE, NULL);
 	notify_id = gconf_client_notify_add (
 		client, "/apps/evolution/mail/display/headers",
 		(GConfClientNotifyFunc) headers_changed_cb,
-		emf, NULL, NULL);
+		closure, (GFreeFunc) free_headers_changed_closure, NULL);
 
 	g_object_set_data_full (
-		G_OBJECT (emf), "reader-header-notify-id",
+		G_OBJECT (formatter), "reader-header-notify-id",
 		GINT_TO_POINTER (notify_id), remove_header_notify_cb);
 
-	headers_changed_cb (client, 0, NULL, emf);
+	headers_changed_cb (client, 0, NULL, closure);
 
 	g_object_unref (client);
 }
+
+static GHashTable *
+mail_reader_get_mail_register (void)
+{
+	SoupSession *session;
+	GHashTable *mails;
+
+	session = webkit_get_default_session ();
+	mails = g_object_get_data (G_OBJECT (session), "mails");
+	if (!mails) {
+		mails = g_hash_table_new_full (g_str_hash, g_str_equal,
+				(GDestroyNotify) g_free, NULL);
+		g_object_set_data_full (
+			G_OBJECT (session), "mails", mails,
+			(GDestroyNotify) g_hash_table_destroy);
+	}
+
+	return mails;
+}
+
+EMailPartList *
+e_mail_reader_lookup_part_list (EMailReader *reader,
+                                const gchar *uri)
+{
+	GHashTable *mails;
+
+	g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+	g_return_val_if_fail (uri && *uri, NULL);
+
+	mails = mail_reader_get_mail_register ();
+	return g_hash_table_lookup (mails, uri);
+}
+
+struct _formatter_weak_ref_closure {
+	GHashTable *part_lists;
+	gchar *mail_uri;
+};
+
+static void
+part_list_weak_ref_cb (gchar *mail_uri,
+                       EMailPartList *part_list)
+{
+	GHashTable *mails;
+
+	mails = mail_reader_get_mail_register ();
+
+	/* When this callback is called, the partslist is being finalized
+	 * so we only remove it from the parts list table. */
+	g_hash_table_remove (mails, mail_uri);
+
+	d(printf("Destroying parts list %p (%s)\n", part_list, mail_uri));
+
+	g_free (mail_uri);
+}
+
+struct format_parser_async_closure_ {
+        EActivity *activity;
+	gchar *mail_uri;
+
+	GFunc user_callback;
+	gpointer user_data;
+};
+
+static void
+format_parser_async_done_cb (GObject *source,
+                             GAsyncResult *result,
+                             gpointer user_data)
+{
+	EMailParser *parser = E_MAIL_PARSER (source);
+	EMailPartList *part_list;
+	GHashTable *mails;
+	struct format_parser_async_closure_ *closure = user_data;
+
+	part_list = e_mail_parser_parse_finish (parser, result, NULL);
+
+	/* When no EMailDisplay holds reference to the part list, then
+	 * the list can be destroyed. */
+	g_object_weak_ref (G_OBJECT (part_list),
+		(GWeakNotify) part_list_weak_ref_cb, g_strdup (closure->mail_uri));
+
+	mails = mail_reader_get_mail_register ();
+	g_hash_table_insert (mails, g_strdup (closure->mail_uri), part_list);
+	d(printf("Registered EMailPartList %s\n", closure->mail_uri));
+
+	if (closure->user_callback)
+		closure->user_callback (part_list, closure->user_data);
+
+	g_object_unref (closure->activity);
+	g_free (closure->mail_uri);
+	g_free (closure);
+
+	g_object_unref (result);
+	g_object_unref (parser);
+}
+
+void
+e_mail_reader_parse_message (EMailReader *reader,
+                             CamelFolder *folder,
+                             const gchar *message_uid,
+                             CamelMimeMessage *message,
+                             GFunc ready_callback,
+                             gpointer user_data)
+{
+	EMailParser *parser;
+	EMailBackend *mail_backend;
+	EMailSession *mail_session;
+	gchar *mail_uri;
+	struct format_parser_async_closure_ *closure;
+
+	mail_uri = e_mail_part_build_uri (folder, message_uid, NULL, NULL);
+
+	mail_backend = e_mail_reader_get_backend (reader);
+	mail_session = e_mail_backend_get_session (mail_backend);
+
+	closure = g_new0 (struct format_parser_async_closure_, 1);
+	parser = e_mail_parser_new (CAMEL_SESSION (mail_session));
+
+	closure->activity = e_mail_reader_new_activity (reader);
+	e_activity_set_text (closure->activity, _("Parsing message"));
+	closure->mail_uri = mail_uri;
+	closure->user_callback = ready_callback;
+	closure->user_data = user_data;
+
+	e_mail_parser_parse (parser, folder, message_uid,
+		message, format_parser_async_done_cb,
+		e_activity_get_cancellable (closure->activity),
+		closure);
+}
diff --git a/mail/e-mail-reader-utils.h b/mail/e-mail-reader-utils.h
index 6913d09..887e399 100644
--- a/mail/e-mail-reader-utils.h
+++ b/mail/e-mail-reader-utils.h
@@ -68,7 +68,22 @@ gchar *		e_mail_reader_header_to_xml	(EMailReaderHeader *header);
 void		e_mail_reader_header_free	(EMailReaderHeader *header);
 
 void		e_mail_reader_connect_headers	(EMailReader *reader,
-						 EMFormat *emf);
+						 EMailFormatter *formatter);
+
+EMailPartList *	e_mail_reader_lookup_part_list	(EMailReader *reader,
+						 const gchar *uri);
+
+void		e_mail_reader_store_part_list	(EMailReader *reader,
+						 const gchar *uri,
+						 EMailPartList *part_list);
+
+void		e_mail_reader_parse_message
+						(EMailReader *reader,
+						 CamelFolder *folder,
+						 const gchar *message_uid,
+						 CamelMimeMessage *message,
+						 GFunc ready_callback,
+						 gpointer user_data);
 
 G_END_DECLS
 
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index af8a0ee..3d0911b 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -53,12 +53,15 @@
 #include "mail/em-event.h"
 #include "mail/em-folder-selector.h"
 #include "mail/em-folder-tree.h"
-#include "mail/em-format-html-display.h"
 #include "mail/em-utils.h"
 #include "mail/mail-autofilter.h"
 #include "mail/mail-vfolder-ui.h"
 #include "mail/message-list.h"
 
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-part-utils.h>
+
 #if HAVE_CLUTTER
 #include <clutter/clutter.h>
 #include <mx/mx.h>
@@ -69,7 +72,7 @@
 	((EMailReaderPrivate *) g_object_get_qdata \
 	(G_OBJECT (obj), quark_private))
 
-#define d(x)
+#define d(x) x
 
 typedef struct _EMailReaderClosure EMailReaderClosure;
 typedef struct _EMailReaderPrivate EMailReaderPrivate;
@@ -85,6 +88,8 @@ struct _EMailReaderPrivate {
 	EMailForwardStyle forward_style;
 	EMailReplyStyle reply_style;
 
+	EMailFormatter *formatter;
+
 	/* This timer runs when the user selects a single message. */
 	guint message_selected_timeout_id;
 
@@ -280,7 +285,7 @@ action_mail_image_save_cb (GtkAction *action,
 {
 	EMailDisplay *display;
 	EWebView *web_view;
-	EMFormat *emf;
+	EMailPartList *parts;
 	const gchar *image_src;
 	CamelMimePart *part;
 	EAttachment *attachment;
@@ -296,13 +301,13 @@ action_mail_image_save_cb (GtkAction *action,
 	if (!image_src)
 		return;
 
-	emf = EM_FORMAT (e_mail_display_get_formatter (display));
-	g_return_if_fail (emf != NULL);
-	g_return_if_fail (emf->message != NULL);
+	parts = e_mail_display_get_parts_list (display);
+	g_return_if_fail (parts != NULL);
+	g_return_if_fail (parts->message != NULL);
 
 	if (g_str_has_prefix (image_src, "cid:")) {
 		part = camel_mime_message_get_part_by_content_id (
-			emf->message, image_src + 4);
+			parts->message, image_src + 4);
 		g_return_if_fail (part != NULL);
 
 		g_object_ref (part);
@@ -371,20 +376,18 @@ action_mail_charset_cb (GtkRadioAction *action,
                         GtkRadioAction *current,
                         EMailReader *reader)
 {
-	EMailDisplay *display;
-	EMFormatHTML *formatter;
+	EMailFormatter *formatter;
 	const gchar *charset;
 
 	if (action != current)
 		return;
 
-	display = e_mail_reader_get_mail_display (reader);
-	formatter = e_mail_display_get_formatter (display);
+	formatter = e_mail_reader_get_formatter (reader);
 	charset = g_object_get_data (G_OBJECT (action), "charset");
 
 	/* Charset for "Default" action will be NULL. */
 	if (formatter)
-		em_format_set_charset (EM_FORMAT (formatter), charset);
+		e_mail_formatter_set_charset (formatter, charset);
 }
 
 static void
@@ -1711,9 +1714,9 @@ action_mail_show_all_headers_cb (GtkToggleAction *action,
 	display = e_mail_reader_get_mail_display (reader);
 
 	if (gtk_toggle_action_get_active (action))
-		e_mail_display_set_mode (display, EM_FORMAT_WRITE_MODE_ALL_HEADERS);
+		e_mail_display_set_mode (display, E_MAIL_FORMATTER_MODE_ALL_HEADERS);
 	else
-		e_mail_display_set_mode (display, EM_FORMAT_WRITE_MODE_NORMAL);
+		e_mail_display_set_mode (display, E_MAIL_FORMATTER_MODE_NORMAL);
 }
 
 struct _source_retrieval_closure {
@@ -1782,13 +1785,13 @@ action_mail_show_source_cb (GtkAction *action,
 	g_return_if_fail (uids != NULL && uids->len == 1);
 	message_uid = g_ptr_array_index (uids, 0);
 
-	browser = e_mail_browser_new (backend, NULL, NULL, EM_FORMAT_WRITE_MODE_SOURCE);
+	browser = e_mail_browser_new (backend, NULL, NULL, E_MAIL_FORMATTER_MODE_SOURCE);
 	e_mail_reader_set_folder (E_MAIL_READER (browser), folder);
 	e_mail_reader_set_message (E_MAIL_READER (browser), message_uid);
 	display = e_mail_reader_get_mail_display (E_MAIL_READER (browser));
 
 	string = g_strdup_printf (_("Retrieving message '%s'"), message_uid);
-	e_mail_display_set_formatter (display, NULL);
+	e_mail_display_set_parts_list (display, NULL);
 	e_mail_display_set_status (display, string);
 	gtk_widget_show (browser);
 
@@ -2664,7 +2667,7 @@ mail_reader_message_seen_cb (EMailReaderClosure *closure)
 {
 	EMailReader *reader;
 	GtkWidget *message_list;
-	EMFormatHTML *formatter;
+	EMailPartList *parts;
 	EMailDisplay *display;
 	CamelMimeMessage *message;
 	const gchar *current_uid;
@@ -2675,7 +2678,7 @@ mail_reader_message_seen_cb (EMailReaderClosure *closure)
 	message_uid = closure->message_uid;
 
 	display = e_mail_reader_get_mail_display (reader);
-	formatter = e_mail_display_get_formatter (display);
+	parts = e_mail_display_get_parts_list (display);
 	message_list = e_mail_reader_get_message_list (reader);
 
 	if (e_tree_is_dragging (E_TREE (message_list)))
@@ -2684,8 +2687,8 @@ mail_reader_message_seen_cb (EMailReaderClosure *closure)
 	current_uid = MESSAGE_LIST (message_list)->cursor_uid;
 	uid_is_current &= (g_strcmp0 (current_uid, message_uid) == 0);
 
-	if (formatter)
-		message = EM_FORMAT (formatter)->message;
+	if (parts)
+		message = parts->message;
 	else
 		message = NULL;
 
@@ -2846,7 +2849,7 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader)
 	CamelFolder *folder;
 	const gchar *cursor_uid;
 	const gchar *format_uid;
-	EMFormat *formatter;
+	EMailPartList *parts;
 
 	priv = E_MAIL_READER_GET_PRIVATE (reader);
 
@@ -2854,10 +2857,10 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader)
 
 	message_list = e_mail_reader_get_message_list (reader);
 	display = e_mail_reader_get_mail_display (reader);
-	formatter = EM_FORMAT (e_mail_display_get_formatter (display));
+	parts = e_mail_display_get_parts_list (display);
 
 	cursor_uid = MESSAGE_LIST (message_list)->cursor_uid;
-	format_uid = formatter ? formatter->message_uid : NULL;
+	format_uid = parts ? parts->message_uid : NULL;
 
 	if (MESSAGE_LIST (message_list)->last_sel_single) {
 		GtkWidget *widget;
@@ -2877,7 +2880,7 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader)
 			gchar *string;
 
 			string = g_strdup_printf (_("Retrieving message '%s'"), cursor_uid);
-			e_mail_display_set_formatter (display, NULL);
+			e_mail_display_set_parts_list (display, NULL);
 			e_mail_display_set_status (display, string);
 			g_free (string);
 
@@ -2900,7 +2903,7 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader)
 			priv->retrieving_message = g_object_ref (cancellable);
 		}
 	} else {
-		e_mail_display_set_formatter (display, NULL);
+		e_mail_display_set_parts_list (display, NULL);
 		priv->restoring_message_selection = FALSE;
 	}
 
@@ -3100,52 +3103,25 @@ mail_reader_folder_loaded (EMailReader *reader)
 	e_mail_reader_update_actions (reader, state);
 }
 
-struct _formatter_weak_ref_closure {
-	GHashTable *formatters;
-	gchar *mail_uri;
-};
-
-static void
-formatter_weak_ref_cb (struct _formatter_weak_ref_closure *data,
-                       EMFormat *formatter)
-{
-	/* When this callback is called, the formatter is being finalized
-	 * so we only remove it from the formatters table. */
-	g_hash_table_remove (data->formatters,
-		data->mail_uri);
-
-	d(printf("Destroying formatter %p (%s)\n", formatter, data->mail_uri));
-
-	/* Destroying the formatter will prevent this callback
-	 * being called, so we can remove the closure data as well */
-	g_hash_table_unref (data->formatters);
-	g_free (data->mail_uri);
-	g_free (data);
-}
-
 struct format_parser_async_closure_ {
+	struct _formatter_weak_ref_closure *weak_ref_closure;
         EMailDisplay *display;
         EActivity *activity;
 };
 
 static void
-format_parser_async_done_cb (GObject *source,
-                             GAsyncResult *result,
-                             gpointer user_data)
+set_mail_display_part_list (EMailPartList *part_list,
+                            gpointer user_data)
 {
-	EMFormat *emf = EM_FORMAT (source);
-	struct format_parser_async_closure_ *closure = user_data;
-
-	e_mail_display_set_formatter (closure->display, EM_FORMAT_HTML (emf));
-	e_mail_display_load (closure->display, emf->uri_base);
+	EMailDisplay *display = user_data;
 
-	g_object_unref (closure->activity);
-	g_object_unref (closure->display);
-	g_free (closure);
+	e_mail_display_set_parts_list (display, part_list);
+	e_mail_display_load (display, NULL);
 
-        /* Remove the reference added when formatter was created,
+	g_object_unref (display);
+        /* Remove the reference added when parts list was created,
          * so that only owners are EMailDisplays */
-	g_object_unref (emf);
+	g_object_unref (part_list);
 }
 
 static void
@@ -3155,67 +3131,23 @@ mail_reader_set_display_formatter_for_message (EMailReader *reader,
                                                CamelMimeMessage *message,
                                                CamelFolder *folder)
 {
-	SoupSession *session;
-	GHashTable *formatters;
-	EMFormat *formatter;
+	EMailPartList *parts;
 	gchar *mail_uri;
 
-	mail_uri = em_format_build_mail_uri (folder, message_uid, NULL, NULL);
+	mail_uri = e_mail_part_build_uri (folder, message_uid, NULL, NULL);
+	parts = e_mail_reader_lookup_part_list (reader, mail_uri);
+	g_free (mail_uri);
 
-	session = webkit_get_default_session ();
-	formatters = g_object_get_data (G_OBJECT (session), "formatters");
-	if (!formatters) {
-		formatters = g_hash_table_new_full (g_str_hash, g_str_equal,
-				(GDestroyNotify) g_free, NULL);
-		g_object_set_data_full (
-			G_OBJECT (session), "formatters", formatters,
-			(GDestroyNotify) g_hash_table_destroy);
-	}
-
-	if ((formatter = g_hash_table_lookup (formatters, mail_uri)) == NULL) {
-		EMailBackend *mail_backend;
-		EMailSession *mail_session;
-		struct _formatter_weak_ref_closure *formatter_data =
-				g_new0 (struct _formatter_weak_ref_closure, 1);
-
-		struct format_parser_async_closure_ *closure;
-
-		formatter_data->formatters = g_hash_table_ref (formatters);
-		formatter_data->mail_uri = g_strdup (mail_uri);
-
-		mail_backend = e_mail_reader_get_backend (reader);
-		mail_session = e_mail_backend_get_session (mail_backend);
-
-		formatter = EM_FORMAT (
-			em_format_html_display_new (
-			CAMEL_SESSION (mail_session)));
-
-		/* When no EMailDisplay holds reference to the formatter, then
-		 * the formatter can be destroyed. */
-		g_object_weak_ref (G_OBJECT (formatter),
-			(GWeakNotify) formatter_weak_ref_cb, formatter_data);
-
-		formatter->message_uid = g_strdup (message_uid);
-		formatter->uri_base = g_strdup (mail_uri);
-
-		e_mail_reader_connect_headers (reader, formatter);
+	if (parts == NULL) {
 
-		closure = g_new0 (struct format_parser_async_closure_, 1);
-		closure->activity = e_mail_reader_new_activity (reader);
-		e_activity_set_text (closure->activity, _("Parsing message"));
-		closure->display = g_object_ref (display);
+		e_mail_reader_parse_message (
+			reader, folder, message_uid, message,
+			(GFunc) set_mail_display_part_list,
+			g_object_ref (display));
 
-		em_format_parse_async (formatter, message, folder,
-			e_activity_get_cancellable (closure->activity),
-			format_parser_async_done_cb, closure);
-
-		/* Don't free the mail_uri!! */
-		g_hash_table_insert (formatters, mail_uri, formatter);
 	} else {
-		e_mail_display_set_formatter (display, EM_FORMAT_HTML (formatter));
-		e_mail_display_load (display, formatter->uri_base);
-
-		g_free (mail_uri);
+		e_mail_display_set_parts_list (display, parts);
+		e_mail_display_load (display, NULL);
 	}
 }
 
@@ -3895,6 +3827,12 @@ e_mail_reader_init (EMailReader *reader,
 	message_list = e_mail_reader_get_message_list (reader);
 	display = e_mail_reader_get_mail_display (reader);
 
+	/* Initialize a private struct. */
+	g_object_set_qdata_full (
+		G_OBJECT (reader), quark_private,
+		g_slice_new0 (EMailReaderPrivate),
+		(GDestroyNotify) mail_reader_private_free);
+
 	if (!init_actions)
 		goto connect_signals;
 
@@ -4114,7 +4052,7 @@ e_mail_reader_init (EMailReader *reader,
 connect_signals:
 
 	if (!connect_signals)
-		goto init_private;
+		return;
 
 	/* Connect signals. */
 	g_signal_connect_swapped (
@@ -4158,15 +4096,6 @@ connect_signals:
 	g_signal_connect_swapped (
 		message_list, "selection-change",
 		G_CALLBACK (e_mail_reader_changed), reader);
-
-init_private:
-
-	/* Initialize a private struct. */
-
-	g_object_set_qdata_full (
-		G_OBJECT (reader), quark_private,
-		g_slice_new0 (EMailReaderPrivate),
-		(GDestroyNotify) mail_reader_private_free);
 }
 
 void
@@ -4805,3 +4734,39 @@ e_mail_reader_avoid_next_mark_as_seen (EMailReader *reader)
 
 	priv->avoid_next_mark_as_seen = TRUE;
 }
+
+EMailFormatter *
+e_mail_reader_get_formatter (EMailReader *reader)
+{
+	EMailReaderPrivate *priv;
+
+	g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+	priv = E_MAIL_READER_GET_PRIVATE (reader);
+	g_return_val_if_fail (priv != NULL, NULL);
+
+	return priv->formatter;
+}
+
+void
+e_mail_reader_set_formatter (EMailReader *reader,
+                             EMailFormatter *formatter)
+{
+	EMailReaderPrivate *priv;
+
+	g_return_if_fail (E_IS_MAIL_READER (reader));
+	g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+
+	priv = E_MAIL_READER_GET_PRIVATE (reader);
+	g_return_if_fail (priv != NULL);
+
+	g_object_ref (formatter);
+
+	if (priv->formatter) {
+		g_object_unref (priv->formatter);
+	}
+
+	priv->formatter = formatter;
+
+	e_mail_reader_connect_headers (reader, formatter);
+}
diff --git a/mail/e-mail-reader.h b/mail/e-mail-reader.h
index 6f03fc0..b33aee7 100644
--- a/mail/e-mail-reader.h
+++ b/mail/e-mail-reader.h
@@ -179,6 +179,10 @@ void		e_mail_reader_enable_show_folder
 void		e_mail_reader_avoid_next_mark_as_seen
 						(EMailReader *reader);
 
+EMailFormatter *	e_mail_reader_get_formatter	(EMailReader *reader);
+void		e_mail_reader_set_formatter	(EMailReader *reader,
+						 EMailFormatter *formatter);
+
 G_END_DECLS
 
 #endif /* E_MAIL_READER_H */
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
index 7522bc5..01c1144 100644
--- a/mail/e-mail-request.c
+++ b/mail/e-mail-request.c
@@ -24,10 +24,14 @@
 #include <libsoup/soup-requester.h>
 #include <libsoup/soup-request-http.h>
 
+#include <webkit/webkit.h>
+
 #include <glib/gi18n.h>
 #include <camel/camel.h>
 
-#include "em-format-html.h"
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-formatter-utils.h>
+#include <em-format/e-mail-formatter-print.h>
 
 #include <e-util/e-icon-factory.h>
 #include <e-util/e-util.h>
@@ -40,15 +44,13 @@
 	((obj), E_TYPE_MAIL_REQUEST, EMailRequestPrivate))
 
 struct _EMailRequestPrivate {
-	EMFormatHTML *efh;
-
 	CamelStream *output_stream;
-	EMFormatPURI *puri;
 	gchar *mime_type;
 
 	gint content_length;
 
 	GHashTable *uri_query;
+	gchar *uri_base;
 
         gchar *ret_mime_type;
 };
@@ -61,14 +63,17 @@ handle_mail_request (GSimpleAsyncResult *res,
                      GCancellable *cancellable)
 {
 	EMailRequest *request = E_MAIL_REQUEST (object);
-	EMFormatHTML *efh = request->priv->efh;
-	EMFormat *emf = EM_FORMAT (efh);
 	GInputStream *stream;
+	EMailFormatter *formatter;
+	EMailPartList *part_list;
+	SoupSession *session;
+	GHashTable *mails;
 	GByteArray *ba;
 	gchar *part_id;
-	EMFormatWriterInfo info = {0};
 	gchar *val;
 
+	EMailFormatterContext context = { 0 };
+
 	if (g_cancellable_is_cancelled (cancellable))
 		return;
 
@@ -76,39 +81,67 @@ handle_mail_request (GSimpleAsyncResult *res,
 		g_object_unref (request->priv->output_stream);
 	}
 
+	session = webkit_get_default_session ();
+	mails = g_object_get_data (G_OBJECT (session), "mails");
+	part_list = g_hash_table_lookup (mails, request->priv->uri_base);
+	g_return_if_fail (part_list != NULL);
+
 	request->priv->output_stream = camel_stream_mem_new ();
 
 	val = g_hash_table_lookup (request->priv->uri_query, "headers_collapsed");
-	if (val)
-		info.headers_collapsed = atoi (val);
+	if (val && atoi (val) == 1)
+		context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED;
 
 	val = g_hash_table_lookup (request->priv->uri_query, "headers_collapsable");
-	if (val)
-		info.headers_collapsable = atoi (val);
+	if (val && atoi (val) == 1)
+		context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE;
 
 	val = g_hash_table_lookup (request->priv->uri_query, "mode");
 	if (val)
-		info.mode = atoi (val);
+		context.mode = atoi (val);
+
+	context.message = part_list->message;
+	context.message_uid = part_list->message_uid;
+	context.folder = part_list->folder;
+	context.parts = part_list->list;
+
+	if (context.mode == E_MAIL_FORMATTER_MODE_PRINTING)
+		formatter = e_mail_formatter_print_new ();
+	else
+		formatter = e_mail_formatter_new ();
 
 	part_id = g_hash_table_lookup (request->priv->uri_query, "part_id");
 	if (part_id) {
+		EMailPart *part;
+		const gchar *mime_type;
 		/* original part_id is owned by the GHashTable */
 		part_id = soup_uri_decode (part_id);
-		request->priv->puri = em_format_find_puri (emf, part_id);
+		part = e_mail_part_list_find_part (part_list, part_id);
 
-		if (request->priv->puri) {
-			em_format_puri_write (request->priv->puri,
-				request->priv->output_stream, &info, cancellable);
+		val = g_hash_table_lookup (request->priv->uri_query, "mime_type");
+		if (val) {
+			mime_type = val;
+		} else {
+			mime_type = NULL;
+		}
+
+		if (context.mode == E_MAIL_FORMATTER_MODE_SOURCE) {
+			mime_type = "application/vnd.evolution.source";
+		}
+
+		if (part) {
+			e_mail_formatter_format_as (
+				formatter, &context, part, request->priv->output_stream,
+				mime_type ? mime_type : part->mime_type, cancellable);
 		} else {
 			g_warning ("Failed to lookup requested part '%s' - this should not happen!", part_id);
 		}
 
 		g_free (part_id);
 	} else {
-		if (info.mode == 0)
-			info.mode = EM_FORMAT_WRITE_MODE_NORMAL;
-
-		em_format_write (emf, request->priv->output_stream, &info, cancellable);
+		e_mail_formatter_format_sync (
+			formatter, part_list, request->priv->output_stream,
+			context.flags, context.mode, cancellable);
 	}
 
 	/* Convert the GString to GInputStream and send it back to WebKit */
@@ -136,10 +169,7 @@ mail_request_finalize (GObject *object)
 {
 	EMailRequest *request = E_MAIL_REQUEST (object);
 
-	if (request->priv->output_stream) {
-		g_object_unref (request->priv->output_stream);
-		request->priv->output_stream = NULL;
-	}
+	g_clear_object (&request->priv->output_stream);
 
 	if (request->priv->mime_type) {
 		g_free (request->priv->mime_type);
@@ -156,9 +186,9 @@ mail_request_finalize (GObject *object)
 		request->priv->ret_mime_type = NULL;
 	}
 
-	if (request->priv->efh) {
-		g_object_unref (request->priv->efh);
-		request->priv->efh = NULL;
+	if (request->priv->uri_base) {
+		g_free (request->priv->uri_base);
+		request->priv->uri_base = NULL;
 	}
 
 	G_OBJECT_CLASS (e_mail_request_parent_class)->finalize (object);
@@ -178,14 +208,11 @@ mail_request_send_async (SoupRequest *request,
                          GAsyncReadyCallback callback,
                          gpointer user_data)
 {
-	SoupSession *session;
 	EMailRequest *emr = E_MAIL_REQUEST (request);
 	GSimpleAsyncResult *simple;
 	SoupURI *uri;
-	GHashTable *formatters;
 	gchar *uri_str;
 
-	session = soup_request_get_session (request);
 	uri = soup_request_get_uri (request);
 
 	d(printf("received request for %s\n", soup_uri_to_string (uri, FALSE)));
@@ -196,18 +223,9 @@ mail_request_send_async (SoupRequest *request,
 		emr->priv->uri_query = NULL;
 	}
 
-	formatters = g_object_get_data (G_OBJECT (session), "formatters");
-					g_return_if_fail (formatters != NULL);
-
 	uri_str = g_strdup_printf (
 		"%s://%s%s", uri->scheme, uri->host, uri->path);
-	emr->priv->efh = g_hash_table_lookup (formatters, uri_str);
-	g_free (uri_str);
-
-	g_return_if_fail (emr->priv->efh);
-
-	/* Make sure the formatter lives until we are finished here */
-	g_object_ref (emr->priv->efh);
+	emr->priv->uri_base = uri_str;
 
 	simple = g_simple_async_result_new (
 		G_OBJECT (request), callback,
@@ -229,10 +247,11 @@ mail_request_send_finish (SoupRequest *request,
 {
 	GInputStream *stream;
 
-	stream = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	stream = g_simple_async_result_get_op_res_gpointer (
+					G_SIMPLE_ASYNC_RESULT (result));
 
 	/* Reset the stream before passing it back to webkit */
-	if (stream && G_IS_SEEKABLE (stream))
+	if (G_IS_INPUT_STREAM (stream) && G_IS_SEEKABLE (stream))
 		g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
 
 	if (!stream) /* We must always return something */
@@ -269,13 +288,8 @@ mail_request_get_content_type (SoupRequest *request)
 
 	if (emr->priv->mime_type) {
 		mime_type = g_strdup (emr->priv->mime_type);
-	} else if (!emr->priv->puri) {
-		mime_type = g_strdup ("text/html");
-	} else if (!emr->priv->puri->mime_type) {
-		CamelContentType *ct = camel_mime_part_get_content_type (emr->priv->puri->part);
-		mime_type = camel_content_type_simple (ct);
 	} else {
-		mime_type = g_strdup (emr->priv->puri->mime_type);
+		mime_type = g_strdup ("text/html");
 	}
 
 	if (g_strcmp0 (mime_type, "text/html") == 0) {
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index 4fe1414..71754a6 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -43,6 +43,9 @@
 #include <libemail-engine/mail-ops.h>
 #include <libemail-engine/mail-tools.h>
 
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-formatter-quote.h>
+
 #include <shell/e-shell.h>
 
 #include <composer/e-msg-composer.h>
@@ -54,10 +57,6 @@
 #include "em-composer-utils.h"
 #include "em-folder-selector.h"
 #include "em-folder-tree.h"
-#include "em-format-html.h"
-#include "em-format-html-print.h"
-#include "em-format-html-display.h"
-#include "em-format-quote.h"
 #include "em-event.h"
 #include "mail-send-recv.h"
 
@@ -958,8 +957,6 @@ composer_print_done_cb (EMailPrinter *emp,
                         GtkPrintOperationResult result,
                         gpointer user_data)
 {
-	EMFormat *emf = user_data;
-	g_object_unref (emf);
 	g_object_unref (emp);
 }
 
@@ -971,23 +968,23 @@ em_utils_composer_print_cb (EMsgComposer *composer,
                             EMailSession *session)
 {
 	EMailPrinter *emp;
-	EMFormatHTMLDisplay *efhd;
+	EMailParser *parser;
+	EMailPartList *parts;
 	const gchar *message_id;
 
-	efhd = em_format_html_display_new (CAMEL_SESSION (session));
+	parser = e_mail_parser_new (CAMEL_SESSION (session));
 
 	message_id = camel_mime_message_get_message_id (message);
-	((EMFormat *) efhd)->message_uid = g_strdup (message_id);
-
-        /* Parse the message */
-	em_format_parse ((EMFormat *) efhd, message, NULL, NULL);
+	parts = e_mail_parser_parse_sync (parser, NULL, g_strdup (message_id), message, NULL);
 
         /* Use EMailPrinter and WebKit to print the message */
-	emp = e_mail_printer_new ((EMFormatHTML *) efhd);
+	emp = e_mail_printer_new (parts);
 	g_signal_connect (emp, "done",
-		G_CALLBACK (composer_print_done_cb), efhd);
+		G_CALLBACK (composer_print_done_cb), NULL);
 
 	e_mail_printer_print (emp, FALSE, NULL);
+
+	g_object_unref (parts);
 }
 
 /* Composing messages... */
@@ -1543,13 +1540,13 @@ emu_update_composers_security (EMsgComposer *composer,
 	shell_settings = e_shell_get_shell_settings (shell);
 
 	sign_by_default =
-		(validity_found & EM_FORMAT_VALIDITY_FOUND_SIGNED) != 0 &&
+		(validity_found & E_MAIL_PART_VALIDITY_SIGNED) != 0 &&
 		e_shell_settings_get_boolean (
 		shell_settings, "composer-sign-reply-if-signed");
 
 	/* Pre-set only for encrypted messages, not for signed */
 	if (sign_by_default) {
-		if (validity_found & EM_FORMAT_VALIDITY_FOUND_SMIME)
+		if (validity_found & E_MAIL_PART_VALIDITY_SMIME)
 			action = E_COMPOSER_ACTION_SMIME_SIGN (composer);
 		else
 			action = E_COMPOSER_ACTION_PGP_SIGN (composer);
@@ -1558,8 +1555,8 @@ emu_update_composers_security (EMsgComposer *composer,
 			GTK_TOGGLE_ACTION (action), TRUE);
 	}
 
-	if (validity_found & EM_FORMAT_VALIDITY_FOUND_ENCRYPTED) {
-		if (validity_found & EM_FORMAT_VALIDITY_FOUND_SMIME)
+	if (validity_found & E_MAIL_PART_VALIDITY_ENCRYPTED) {
+		if (validity_found & E_MAIL_PART_VALIDITY_SMIME)
 			action = E_COMPOSER_ACTION_SMIME_ENCRYPT (composer);
 		else
 			action = E_COMPOSER_ACTION_PGP_ENCRYPT (composer);
@@ -1703,9 +1700,9 @@ forward_non_attached (EShell *shell,
 	guint32 validity_found = 0;
 	guint32 flags;
 
-	flags = EM_FORMAT_QUOTE_HEADERS | EM_FORMAT_QUOTE_KEEP_SIG;
+	flags = E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS | E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG;
 	if (style == E_MAIL_FORWARD_STYLE_QUOTED)
-		flags |= EM_FORMAT_QUOTE_CITE;
+		flags |= E_MAIL_FORMATTER_QUOTE_FLAG_CITE;
 
 	forward = quoting_text (QUOTING_FORWARD);
 	text = em_utils_message_to_html (
@@ -2760,7 +2757,7 @@ static void
 composer_set_body (EMsgComposer *composer,
                    CamelMimeMessage *message,
                    EMailReplyStyle style,
-                   EMFormat *source)
+                   EMailPartList *parts_list)
 {
 	gchar *text, *credits, *original;
 	CamelMimePart *part;
@@ -2788,8 +2785,8 @@ composer_set_body (EMsgComposer *composer,
 	case E_MAIL_REPLY_STYLE_OUTLOOK:
 		original = quoting_text (QUOTING_ORIGINAL);
 		text = em_utils_message_to_html (
-			session, message, original, EM_FORMAT_QUOTE_HEADERS,
-			source, start_bottom ? "<BR>" : NULL, &validity_found);
+			session, message, original, E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS,
+			parts_list, start_bottom ? "<BR>" : NULL, &validity_found);
 		e_msg_composer_set_body_text (composer, text, TRUE);
 		has_body_text = text && *text;
 		g_free (text);
@@ -2802,8 +2799,8 @@ composer_set_body (EMsgComposer *composer,
 		/* do what any sane user would want when replying... */
 		credits = attribution_format (message);
 		text = em_utils_message_to_html (
-			session, message, credits, EM_FORMAT_QUOTE_CITE,
-			source, start_bottom ? "<BR>" : NULL, &validity_found);
+			session, message, credits, E_MAIL_FORMATTER_QUOTE_FLAG_CITE,
+			parts_list, start_bottom ? "<BR>" : NULL, &validity_found);
 		g_free (credits);
 		e_msg_composer_set_body_text (composer, text, TRUE);
 		has_body_text = text && *text;
@@ -2842,7 +2839,7 @@ composer_set_body (EMsgComposer *composer,
 gchar *
 em_utils_construct_composer_text (CamelSession *session,
                                   CamelMimeMessage *message,
-                                  EMFormat *source)
+                                  EMailPartList *parts_list)
 {
 	gchar *text, *credits;
 	gboolean start_bottom = 0;
@@ -2851,8 +2848,8 @@ em_utils_construct_composer_text (CamelSession *session,
 
 	credits = attribution_format (message);
 	text = em_utils_message_to_html (
-		session, message, credits, EM_FORMAT_QUOTE_CITE,
-		source, start_bottom ? "<BR>" : NULL, NULL);
+		session, message, credits, E_MAIL_FORMATTER_QUOTE_FLAG_CITE,
+		parts_list, start_bottom ? "<BR>" : NULL, NULL);
 	g_free (credits);
 
 	return text;
@@ -2881,7 +2878,7 @@ em_utils_reply_to_message (EShell *shell,
                            const gchar *message_uid,
                            EMailReplyType type,
                            EMailReplyStyle style,
-                           EMFormat *source_formatter,
+                           EMailPartList *parts_list,
                            CamelInternetAddress *address)
 {
 	ESourceRegistry *registry;
@@ -2956,7 +2953,7 @@ em_utils_reply_to_message (EShell *shell,
 	g_object_unref (to);
 	g_object_unref (cc);
 
-	composer_set_body (composer, message, style, source_formatter);
+	composer_set_body (composer, message, style, parts_list);
 
 	if (folder != NULL) {
 		gchar *folder_uri;
diff --git a/mail/em-composer-utils.h b/mail/em-composer-utils.h
index a525cec..93d87bf 100644
--- a/mail/em-composer-utils.h
+++ b/mail/em-composer-utils.h
@@ -24,7 +24,7 @@
 #ifndef EM_COMPOSER_UTILS_H
 #define EM_COMPOSER_UTILS_H
 
-#include <em-format/em-format.h>
+#include <em-format/e-mail-part.h>
 #include <mail/e-mail-backend.h>
 #include <mail/e-mail-reader.h>
 #include <composer/e-msg-composer.h>
@@ -62,7 +62,7 @@ void		em_utils_redirect_message	(EShell *shell,
 gchar *		em_utils_construct_composer_text
 						(CamelSession *session,
 						 CamelMimeMessage *message,
-						 EMFormat *source_formatter);
+						 EMailPartList *source_formatter);
 gboolean	em_utils_is_munged_list_message	(CamelMimeMessage *message);
 void		em_utils_get_reply_sender	(CamelMimeMessage *message,
 						 CamelInternetAddress *to,
@@ -78,7 +78,7 @@ EMsgComposer *	em_utils_reply_to_message	(EShell *shell,
 						 const gchar *message_uid,
 						 EMailReplyType type,
 						 EMailReplyStyle style,
-						 EMFormat *source,
+						 EMailPartList *source,
 						 CamelInternetAddress *address);
 EDestination **	em_utils_camel_address_to_destination
 						(CamelInternetAddress *iaddr);
diff --git a/mail/em-utils.c b/mail/em-utils.c
index bf75253..9be80fb 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -56,6 +56,9 @@
 #include <shell/e-shell.h>
 #include <widgets/misc/e-attachment.h>
 
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-formatter-quote.h>
+
 #include <libemail-utils/mail-mt.h>
 
 #include <libemail-engine/e-mail-folder-utils.h>
@@ -65,13 +68,11 @@
 
 #include "e-mail-tag-editor.h"
 #include "em-composer-utils.h"
-#include "em-format-html-display.h"
-#include "em-format-html-print.h"
 #include "em-utils.h"
 #include "e-mail-printer.h"
-#include "em-format/em-format-quote.h"
 
 /* XXX This is a dirty hack on a dirty hack.  We really need
+#include <em-format/e-mail-print-formatter.h>
  *     to rework or get rid of the functions that use this. */
 extern const gchar *shell_builtin_backend;
 
@@ -616,20 +617,22 @@ do_print_msg_to_file (GObject *source,
                       GAsyncResult *result,
                       gpointer user_data)
 {
-
-	EMFormatHTML *efh = EM_FORMAT_HTML (source);
+	EMailParser *parser;
+	EMailPartList *parts_list;
 	gchar *filename = user_data;
-
 	EMailPrinter *printer;
 
-	printer = e_mail_printer_new (efh);
+	parser = E_MAIL_PARSER (source);
+	parts_list = e_mail_parser_parse_finish (parser, result, NULL);
+
+	printer = e_mail_printer_new (parts_list);
 	e_mail_printer_set_export_filename (printer, filename);
 	g_signal_connect_swapped (printer, "done",
 		G_CALLBACK (g_object_unref), printer);
 
 	e_mail_printer_print (printer, TRUE, NULL);
 
-	g_object_unref (efh);
+	g_object_unref (parser);
 }
 
 static gboolean
@@ -637,7 +640,7 @@ em_utils_print_messages_to_file (CamelFolder *folder,
                                  const gchar *uid,
                                  const gchar *filename)
 {
-	EMFormatHTMLDisplay *efhd;
+	EMailParser *parser;
 	CamelMimeMessage *message;
 	CamelStore *parent_store;
 	CamelSession *session;
@@ -649,11 +652,10 @@ em_utils_print_messages_to_file (CamelFolder *folder,
 	parent_store = camel_folder_get_parent_store (folder);
 	session = camel_service_get_session (CAMEL_SERVICE (parent_store));
 
-	efhd = em_format_html_display_new (session);
-	((EMFormat *) efhd)->message_uid = g_strdup (uid);
+	parser = e_mail_parser_new (session);
 
-	em_format_parse_async ((EMFormat *) efhd, message, folder, NULL,
-		(GAsyncReadyCallback) do_print_msg_to_file, g_strdup (filename));
+	e_mail_parser_parse (parser, folder, uid, message,
+		(GAsyncReadyCallback) do_print_msg_to_file, NULL,  g_strdup (filename));
 
 	return TRUE;
 }
@@ -1180,13 +1182,19 @@ em_utils_message_to_html (CamelSession *session,
                           CamelMimeMessage *message,
                           const gchar *credits,
                           guint32 flags,
-                          EMFormat *source,
+                          EMailPartList *parts_list,
                           const gchar *append,
                           guint32 *validity_found)
 {
-	EMFormatQuote *emfq;
+	EMailFormatter *formatter;
+	EMailParser *parser;
 	CamelStream *mem;
 	GByteArray *buf;
+	EShell *shell;
+	GtkWindow *window;
+
+	shell = e_shell_get_default ();
+	window = e_shell_get_active_window (shell);
 
 	g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL);
 
@@ -1194,10 +1202,12 @@ em_utils_message_to_html (CamelSession *session,
 	mem = camel_stream_mem_new ();
 	camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (mem), buf);
 
-	emfq = em_format_quote_new (session, credits, mem, flags);
-	em_format_set_composer ((EMFormat *) emfq, TRUE);
+	formatter = e_mail_formatter_quote_new (credits, flags);
+	e_mail_formatter_set_style (formatter,
+		gtk_widget_get_style (GTK_WIDGET (window)),
+		gtk_widget_get_state (GTK_WIDGET (window)));
 
-	if (!source) {
+	if (!parts_list) {
 		GSettings *settings;
 		gchar *charset;
 
@@ -1205,37 +1215,38 @@ em_utils_message_to_html (CamelSession *session,
 		 *       current view, not the global setting. */
 		settings = g_settings_new ("org.gnome.evolution.mail");
 		charset = g_settings_get_string (settings, "charset");
-		em_format_set_default_charset ((EMFormat *) emfq, charset);
+		if (charset && *charset)
+			e_mail_formatter_set_default_charset (formatter, charset);
 		g_object_unref (settings);
 		g_free (charset);
-	}
 
-	/* FIXME Not passing a GCancellable here. */
-	em_format_parse (EM_FORMAT (emfq), message, NULL, NULL);
+		parser = e_mail_parser_new (session);
+		parts_list = e_mail_parser_parse_sync (parser, NULL, NULL, message, NULL);
+	}
 
 	if (validity_found) {
-		GList *iter;
-		EMFormat *emf = (EMFormat *) emfq;
+		GSList *iter;
 
 		if (validity_found)
 			*validity_found = 0;
 
 		/* Return all found validities */
-		for (iter = emf->mail_part_list; iter; iter = iter->next) {
+		for (iter = parts_list->list; iter; iter = iter->next) {
 
-			EMFormatPURI *puri = iter->data;
-			if (!puri)
+			EMailPart *part = iter->data;
+			if (!part)
 				continue;
 
-			if (*validity_found && puri->validity_type)
-				*validity_found |= puri->validity_type;
+			if (*validity_found && part->validity_type)
+				*validity_found |= part->validity_type;
 		}
 
 	}
 
-	em_format_quote_write (emfq, mem, NULL);
-
-	g_object_unref (emfq);
+	e_mail_formatter_format_sync (
+		formatter, parts_list, mem, 0,
+		E_MAIL_FORMATTER_MODE_PRINTING, NULL);
+	g_object_unref (formatter);
 
 	if (append && *append)
 		camel_stream_write_string (mem, append, NULL, NULL);
diff --git a/mail/em-utils.h b/mail/em-utils.h
index 092b759..db286eb 100644
--- a/mail/em-utils.h
+++ b/mail/em-utils.h
@@ -35,7 +35,7 @@
 
 G_BEGIN_DECLS
 
-struct _EMFormat;
+struct _EMailPartList;
 struct _EShell;
 
 gboolean em_utils_ask_open_many (GtkWindow *parent, gint how_many);
@@ -66,7 +66,7 @@ void em_utils_selection_get_urilist (GtkSelectionData *data, CamelFolder *folder
 EProxy *	em_utils_get_proxy		(void);
 
 /* FIXME: should this have an override charset? */
-gchar *em_utils_message_to_html (CamelSession *session, CamelMimeMessage *msg, const gchar *credits, guint32 flags, struct _EMFormat *source, const gchar *append, guint32 *validity_found);
+gchar *em_utils_message_to_html (CamelSession *session, CamelMimeMessage *msg, const gchar *credits, guint32 flags, struct _EMailPartList *parts_list, const gchar *append, guint32 *validity_found);
 
 void		em_utils_empty_trash		(GtkWidget *parent,
 						 EMailSession *session);
diff --git a/modules/mail/e-mail-config-format-html.c b/modules/mail/e-mail-config-format-html.c
index 527f720..cbedecf 100644
--- a/modules/mail/e-mail-config-format-html.c
+++ b/modules/mail/e-mail-config-format-html.c
@@ -26,7 +26,7 @@
 
 #include <shell/e-shell.h>
 #include <e-util/e-util.h>
-#include <mail/em-format-html.h>
+#include <em-format/e-mail-formatter.h>
 
 static gpointer parent_class;
 
@@ -95,7 +95,7 @@ mail_config_format_html_class_init (EExtensionClass *class)
 	object_class = G_OBJECT_CLASS (class);
 	object_class->constructed = mail_config_format_html_constructed;
 
-	class->extensible_type = EM_TYPE_FORMAT_HTML;
+	class->extensible_type = E_TYPE_MAIL_FORMATTER;
 }
 
 void
diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c
index f5bb100..3aecfd9 100644
--- a/modules/mail/e-mail-shell-backend.c
+++ b/modules/mail/e-mail-shell-backend.c
@@ -53,14 +53,16 @@
 #include <mail/e-mail-reader.h>
 #include <mail/em-composer-utils.h>
 #include <mail/em-folder-utils.h>
-#include <mail/em-format-hook.h>
-#include <mail/em-format-html-display.h>
 #include <mail/em-utils.h>
 #include <mail/mail-send-recv.h>
 #include <mail/mail-vfolder-ui.h>
 #include <mail/importers/mail-importer.h>
 #include <mail/e-mail-ui-session.h>
 
+#include <em-format/e-mail-parser.h>
+#include <em-format/e-mail-formatter.h>
+#include <em-format/e-mail-part-utils.h>
+
 #include "e-mail-shell-settings.h"
 #include "e-mail-shell-sidebar.h"
 #include "e-mail-shell-view.h"
@@ -447,14 +449,6 @@ mail_shell_backend_constructed (GObject *object)
 	/* Chain up to parent's constructed() method. */
 	G_OBJECT_CLASS (e_mail_shell_backend_parent_class)->constructed (object);
 
-	/* Register format types for EMFormatHook. */
-	em_format_hook_register_type (em_format_get_type ());
-	em_format_hook_register_type (em_format_html_get_type ());
-	em_format_hook_register_type (em_format_html_display_get_type ());
-
-	/* Register plugin hook types. */
-	em_format_hook_get_type ();
-
 	mail_shell_backend_init_importers ();
 
 	g_signal_connect (
@@ -851,13 +845,35 @@ message_parsed_cb (GObject *source_object,
                    GAsyncResult *res,
                    gpointer user_data)
 {
-	EMFormatHTML *formatter = EM_FORMAT_HTML (source_object);
+	EMailParser *parser = E_MAIL_PARSER (source_object);
+	EMailPartList *parts_list;
 	GObject *preview = user_data;
 	EMailDisplay *display;
+	SoupSession *soup_session;
+	GHashTable *mails;
+	gchar *mail_uri;
 
 	display = g_object_get_data (preview, "mbox-imp-display");
-	e_mail_display_set_formatter (display, formatter);
-	e_mail_display_load (display, EM_FORMAT (formatter)->uri_base);
+
+	parts_list = e_mail_parser_parse_finish (parser, res, NULL);
+
+	soup_session = webkit_get_default_session ();
+	mails = g_object_get_data (G_OBJECT (soup_session), "mails");
+	if (!mails) {
+		mails = g_hash_table_new_full (g_str_hash, g_str_equal,
+			(GDestroyNotify) g_free, NULL);
+		g_object_set_data (
+			G_OBJECT (soup_session), "mails", mails);
+	}
+	mail_uri = e_mail_part_build_uri (
+		parts_list->folder, parts_list->message_uid, NULL, NULL);
+
+	g_hash_table_insert (mails, mail_uri, parts_list);
+
+	e_mail_display_set_parts_list (display, parts_list);
+	e_mail_display_load (display, NULL);
+
+	g_object_unref (parts_list);
 }
 
 /* utility functions for mbox importer */
@@ -883,12 +899,9 @@ mbox_fill_preview_cb (GObject *preview,
 {
 	EShell *shell;
 	EMailDisplay *display;
-	EMFormat *formatter;
-	GHashTable *formatters;
-	SoupSession *soup_session;
+	EMailParser *parser;
 	EMailSession *mail_session;
 	ESourceRegistry *registry;
-	gchar *mail_uri;
 
 	g_return_if_fail (preview != NULL);
 	g_return_if_fail (msg != NULL);
@@ -896,33 +909,13 @@ mbox_fill_preview_cb (GObject *preview,
 	display = g_object_get_data (preview, "mbox-imp-display");
 	g_return_if_fail (display != NULL);
 
-	soup_session = webkit_get_default_session ();
-	formatters = g_object_get_data (G_OBJECT (soup_session), "formatters");
-	if (!formatters) {
-		formatters = g_hash_table_new_full (g_str_hash, g_str_equal,
-			(GDestroyNotify) g_free, NULL);
-		g_object_set_data (
-			G_OBJECT (soup_session), "formatters", formatters);
-	}
-
-	mail_uri = em_format_build_mail_uri (NULL, msg->message_id, NULL, NULL);
-
 	shell = e_shell_get_default ();
 	registry = e_shell_get_registry (shell);
 	mail_session = e_mail_session_new (registry);
 
-	formatter = EM_FORMAT (
-		em_format_html_display_new (
-		CAMEL_SESSION (mail_session)));
-	formatter->message_uid = g_strdup (msg->message_id);
-	formatter->uri_base = g_strdup (mail_uri);
-
-        /* Don't free the mail_uri!! */
-	g_hash_table_insert (formatters, mail_uri, formatter);
-
-	em_format_parse_async (
-		formatter, msg, NULL, NULL,
-		message_parsed_cb, preview);
+	parser = e_mail_parser_new (CAMEL_SESSION (mail_session));
+	e_mail_parser_parse (parser, NULL, msg->message_id, msg,
+		message_parsed_cb, NULL, preview);
 
 	g_object_unref (mail_session);
 }
diff --git a/modules/mail/e-mail-shell-content.h b/modules/mail/e-mail-shell-content.h
index b3eecbe..ff8fb94 100644
--- a/modules/mail/e-mail-shell-content.h
+++ b/modules/mail/e-mail-shell-content.h
@@ -26,7 +26,6 @@
 #include <shell/e-shell-searchbar.h>
 #include <shell/e-shell-view.h>
 #include <mail/e-mail-view.h>
-#include <mail/em-format-html-display.h>
 
 /* Standard GObject macros */
 #define E_TYPE_MAIL_SHELL_CONTENT \
diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c
index afe347c..3468339 100644
--- a/modules/mail/e-mail-shell-view-actions.c
+++ b/modules/mail/e-mail-shell-view-actions.c
@@ -145,7 +145,7 @@ action_mail_account_properties_cb (GtkAction *action,
 	registry = e_shell_get_registry (shell);
 	source = e_source_registry_ref_source (registry, uid);
 	g_return_if_fail (source != NULL);
-	
+
 	e_mail_shell_backend_edit_account (
 		E_MAIL_SHELL_BACKEND (shell_backend),
 		GTK_WINDOW (shell_window), source);
diff --git a/modules/mail/em-mailer-prefs.c b/modules/mail/em-mailer-prefs.c
index 00334d7..9262ff8 100644
--- a/modules/mail/em-mailer-prefs.c
+++ b/modules/mail/em-mailer-prefs.c
@@ -28,7 +28,6 @@
 #include <glib/gi18n-lib.h>
 
 #include "em-mailer-prefs.h"
-#include "em-format/em-format.h"
 
 #include <gtkhtml/gtkhtml-properties.h>
 #include <libxml/tree.h>
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am
index 68b37b9..6b81d16 100644
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@ -11,6 +11,7 @@ widgetsinclude_HEADERS =			\
 	e-alarm-selector.h			\
 	e-alert-bar.h				\
 	e-attachment.h				\
+	e-attachment-bar.h			\
 	e-attachment-button.h			\
 	e-attachment-dialog.h			\
 	e-attachment-handler.h			\
@@ -100,6 +101,7 @@ libemiscwidgets_la_SOURCES =			\
 	e-alarm-selector.c			\
 	e-alert-bar.c				\
 	e-attachment.c				\
+	e-attachment-bar.c			\
 	e-attachment-button.c			\
 	e-attachment-dialog.c			\
 	e-attachment-handler.c			\
diff --git a/mail/e-mail-attachment-bar.c b/widgets/misc/e-attachment-bar.c
similarity index 73%
rename from mail/e-mail-attachment-bar.c
rename to widgets/misc/e-attachment-bar.c
index 495e327..d7c90df 100644
--- a/mail/e-mail-attachment-bar.c
+++ b/widgets/misc/e-attachment-bar.c
@@ -1,5 +1,5 @@
 /*
- * e-mail-attachment-bar.c
+ * e-attachment-bar.c
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,7 +23,7 @@
 #include <config.h>
 #endif
 
-#include "e-mail-attachment-bar.h"
+#include "e-attachment-bar.h"
 
 #include <glib/gi18n.h>
 
@@ -31,13 +31,13 @@
 #include "e-attachment-icon-view.h"
 #include "e-attachment-tree-view.h"
 
-#define E_MAIL_ATTACHMENT_BAR_GET_PRIVATE(obj) \
+#define E_ATTACHMENT_BAR_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
-	((obj), E_TYPE_MAIL_ATTACHMENT_BAR, EMailAttachmentBarPrivate))
+	((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBarPrivate))
 
 #define NUM_VIEWS 2
 
-struct _EMailAttachmentBarPrivate {
+struct _EAttachmentBarPrivate {
 	GtkTreeModel *model;
 	GtkWidget *vbox;
 	GtkWidget *expander;
@@ -65,19 +65,19 @@ enum {
 };
 
 /* Forward Declarations */
-static void	e_mail_attachment_bar_interface_init
+static void	e_attachment_bar_interface_init
 				(EAttachmentViewInterface *interface);
 
 G_DEFINE_TYPE_WITH_CODE (
-	EMailAttachmentBar,
-	e_mail_attachment_bar,
+	EAttachmentBar,
+	e_attachment_bar,
 	GTK_TYPE_VBOX,
 	G_IMPLEMENT_INTERFACE (
 		E_TYPE_ATTACHMENT_VIEW,
-		e_mail_attachment_bar_interface_init))
+		e_attachment_bar_interface_init))
 
 static void
-mail_attachment_bar_update_status (EMailAttachmentBar *bar)
+attachment_bar_update_status (EAttachmentBar *bar)
 {
 	EAttachmentStore *store;
 	GtkActivatable *activatable;
@@ -119,8 +119,8 @@ mail_attachment_bar_update_status (EMailAttachmentBar *bar)
 }
 
 static void
-mail_attachment_bar_set_store (EMailAttachmentBar *bar,
-                               EAttachmentStore *store)
+attachment_bar_set_store (EAttachmentBar *bar,
+                          EAttachmentStore *store)
 {
 	g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
 
@@ -131,28 +131,30 @@ mail_attachment_bar_set_store (EMailAttachmentBar *bar,
 	gtk_tree_view_set_model (GTK_TREE_VIEW (bar->priv->tree_view),
 		bar->priv->model);
 
-	g_signal_connect_swapped (
+	g_signal_connect_object (
 		bar->priv->model, "notify::num-attachments",
-		G_CALLBACK (mail_attachment_bar_update_status), bar);
+		G_CALLBACK (attachment_bar_update_status), bar,
+		G_CONNECT_SWAPPED);
 
-	g_signal_connect_swapped (
+	g_signal_connect_object (
 		bar->priv->model, "notify::total-size",
-		G_CALLBACK (mail_attachment_bar_update_status), bar);
+		G_CALLBACK (attachment_bar_update_status), bar,
+		G_CONNECT_SWAPPED);
 
 	/* Initialize */
-	mail_attachment_bar_update_status (bar);
+	attachment_bar_update_status (bar);
 }
 
 static void
-mail_attachment_bar_set_property (GObject *object,
-                                  guint property_id,
-                                  const GValue *value,
-                                  GParamSpec *pspec)
+attachment_bar_set_property (GObject *object,
+                             guint property_id,
+                             const GValue *value,
+                             GParamSpec *pspec)
 {
 	switch (property_id) {
 		case PROP_ACTIVE_VIEW:
-				e_mail_attachment_bar_set_active_view (
-				E_MAIL_ATTACHMENT_BAR (object),
+				e_attachment_bar_set_active_view (
+				E_ATTACHMENT_BAR (object),
 				g_value_get_int (value));
 			return;
 
@@ -169,13 +171,13 @@ mail_attachment_bar_set_property (GObject *object,
 			return;
 
 		case PROP_EXPANDED:
-			e_mail_attachment_bar_set_expanded (
-				E_MAIL_ATTACHMENT_BAR (object),
+			e_attachment_bar_set_expanded (
+				E_ATTACHMENT_BAR (object),
 				g_value_get_boolean (value));
 			return;
 		case PROP_STORE:
-			mail_attachment_bar_set_store (
-				E_MAIL_ATTACHMENT_BAR (object),
+			attachment_bar_set_store (
+				E_ATTACHMENT_BAR (object),
 				g_value_get_object (value));
 			return;
 	}
@@ -184,17 +186,17 @@ mail_attachment_bar_set_property (GObject *object,
 }
 
 static void
-mail_attachment_bar_get_property (GObject *object,
-                                  guint property_id,
-                                  GValue *value,
-                                  GParamSpec *pspec)
+attachment_bar_get_property (GObject *object,
+                             guint property_id,
+                             GValue *value,
+                             GParamSpec *pspec)
 {
 	switch (property_id) {
 		case PROP_ACTIVE_VIEW:
 			g_value_set_int (
 				value,
-				e_mail_attachment_bar_get_active_view (
-				E_MAIL_ATTACHMENT_BAR (object)));
+				e_attachment_bar_get_active_view (
+				E_ATTACHMENT_BAR (object)));
 			return;
 
 		case PROP_DRAGGING:
@@ -214,25 +216,25 @@ mail_attachment_bar_get_property (GObject *object,
 		case PROP_EXPANDED:
 			g_value_set_boolean (
 				value,
-				e_mail_attachment_bar_get_expanded (
-				E_MAIL_ATTACHMENT_BAR (object)));
+				e_attachment_bar_get_expanded (
+				E_ATTACHMENT_BAR (object)));
 			return;
 		case PROP_STORE:
 			g_value_set_object (
 				value,
-				e_mail_attachment_bar_get_store (
-				E_MAIL_ATTACHMENT_BAR (object)));
+				e_attachment_bar_get_store (
+				E_ATTACHMENT_BAR (object)));
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
 static void
-mail_attachment_bar_dispose (GObject *object)
+attachment_bar_dispose (GObject *object)
 {
-	EMailAttachmentBarPrivate *priv;
+	EAttachmentBarPrivate *priv;
 
-	priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (object);
+	priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
 
 	if (priv->model != NULL) {
 		g_object_unref (priv->model);
@@ -295,16 +297,16 @@ mail_attachment_bar_dispose (GObject *object)
 	}
 
 	/* Chain up to parent's dispose() method. */
-	G_OBJECT_CLASS (e_mail_attachment_bar_parent_class)->dispose (object);
+	G_OBJECT_CLASS (e_attachment_bar_parent_class)->dispose (object);
 }
 
 static void
-mail_attachment_bar_constructed (GObject *object)
+attachment_bar_constructed (GObject *object)
 {
-	EMailAttachmentBarPrivate *priv;
+	EAttachmentBarPrivate *priv;
 	GSettings *settings;
 
-	priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (object);
+	priv = E_ATTACHMENT_BAR_GET_PRIVATE (object);
 
 	/* Set up property-to-property bindings. */
 
@@ -365,131 +367,131 @@ mail_attachment_bar_constructed (GObject *object)
 	g_object_unref (settings);
 
 	/* Chain up to parent's constructed() method. */
-	G_OBJECT_CLASS (e_mail_attachment_bar_parent_class)->constructed (object);
+	G_OBJECT_CLASS (e_attachment_bar_parent_class)->constructed (object);
 }
 
 static EAttachmentViewPrivate *
-mail_attachment_bar_get_private (EAttachmentView *view)
+attachment_bar_get_private (EAttachmentView *view)
 {
-	EMailAttachmentBar *bar;
+	EAttachmentBar *bar;
 
-	bar = E_MAIL_ATTACHMENT_BAR (view);
+	bar = E_ATTACHMENT_BAR (view);
 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
 
 	return e_attachment_view_get_private (view);
 }
 
 static GtkTreePath *
-mail_attachment_bar_get_path_at_pos (EAttachmentView *view,
-                                     gint x,
-                                     gint y)
+attachment_bar_get_path_at_pos (EAttachmentView *view,
+                                gint x,
+                                gint y)
 {
-	EMailAttachmentBar *bar;
+	EAttachmentBar *bar;
 
-	bar = E_MAIL_ATTACHMENT_BAR (view);
+	bar = E_ATTACHMENT_BAR (view);
 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
 
 	return e_attachment_view_get_path_at_pos (view, x, y);
 }
 
 static EAttachmentStore *
-mail_attachment_bar_get_store (EAttachmentView *view)
+attachment_bar_get_store (EAttachmentView *view)
 {
-	return e_mail_attachment_bar_get_store (E_MAIL_ATTACHMENT_BAR (view));
+	return e_attachment_bar_get_store (E_ATTACHMENT_BAR (view));
 }
 
 static GList *
-mail_attachment_bar_get_selected_paths (EAttachmentView *view)
+attachment_bar_get_selected_paths (EAttachmentView *view)
 {
-	EMailAttachmentBar *bar;
+	EAttachmentBar *bar;
 
-	bar = E_MAIL_ATTACHMENT_BAR (view);
+	bar = E_ATTACHMENT_BAR (view);
 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
 
 	return e_attachment_view_get_selected_paths (view);
 }
 
 static gboolean
-mail_attachment_bar_path_is_selected (EAttachmentView *view,
-                                      GtkTreePath *path)
+attachment_bar_path_is_selected (EAttachmentView *view,
+                                 GtkTreePath *path)
 {
-	EMailAttachmentBar *bar;
+	EAttachmentBar *bar;
 
-	bar = E_MAIL_ATTACHMENT_BAR (view);
+	bar = E_ATTACHMENT_BAR (view);
 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
 
 	return e_attachment_view_path_is_selected (view, path);
 }
 
 static void
-mail_attachment_bar_select_path (EAttachmentView *view,
-                                 GtkTreePath *path)
+attachment_bar_select_path (EAttachmentView *view,
+                            GtkTreePath *path)
 {
-	EMailAttachmentBar *bar;
+	EAttachmentBar *bar;
 
-	bar = E_MAIL_ATTACHMENT_BAR (view);
+	bar = E_ATTACHMENT_BAR (view);
 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
 
 	e_attachment_view_select_path (view, path);
 }
 
 static void
-mail_attachment_bar_unselect_path (EAttachmentView *view,
-                                   GtkTreePath *path)
+attachment_bar_unselect_path (EAttachmentView *view,
+                              GtkTreePath *path)
 {
-	EMailAttachmentBar *bar;
+	EAttachmentBar *bar;
 
-	bar = E_MAIL_ATTACHMENT_BAR (view);
+	bar = E_ATTACHMENT_BAR (view);
 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
 
 	e_attachment_view_unselect_path (view, path);
 }
 
 static void
-mail_attachment_bar_select_all (EAttachmentView *view)
+attachment_bar_select_all (EAttachmentView *view)
 {
-	EMailAttachmentBar *bar;
+	EAttachmentBar *bar;
 
-	bar = E_MAIL_ATTACHMENT_BAR (view);
+	bar = E_ATTACHMENT_BAR (view);
 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
 
 	e_attachment_view_select_all (view);
 }
 
 static void
-mail_attachment_bar_unselect_all (EAttachmentView *view)
+attachment_bar_unselect_all (EAttachmentView *view)
 {
-	EMailAttachmentBar *bar;
+	EAttachmentBar *bar;
 
-	bar = E_MAIL_ATTACHMENT_BAR (view);
+	bar = E_ATTACHMENT_BAR (view);
 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
 
 	e_attachment_view_unselect_all (view);
 }
 
 static void
-mail_attachment_bar_update_actions (EAttachmentView *view)
+attachment_bar_update_actions (EAttachmentView *view)
 {
-	EMailAttachmentBar *bar;
+	EAttachmentBar *bar;
 
-	bar = E_MAIL_ATTACHMENT_BAR (view);
+	bar = E_ATTACHMENT_BAR (view);
 	view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
 
 	e_attachment_view_update_actions (view);
 }
 
 static void
-e_mail_attachment_bar_class_init (EMailAttachmentBarClass *class)
+e_attachment_bar_class_init (EAttachmentBarClass *class)
 {
 	GObjectClass *object_class;
 
-	g_type_class_add_private (class, sizeof (EMailAttachmentBarPrivate));
+	g_type_class_add_private (class, sizeof (EAttachmentBarPrivate));
 
 	object_class = G_OBJECT_CLASS (class);
-	object_class->set_property = mail_attachment_bar_set_property;
-	object_class->get_property = mail_attachment_bar_get_property;
-	object_class->dispose = mail_attachment_bar_dispose;
-	object_class->constructed = mail_attachment_bar_constructed;
+	object_class->set_property = attachment_bar_set_property;
+	object_class->get_property = attachment_bar_get_property;
+	object_class->dispose = attachment_bar_dispose;
+	object_class->constructed = attachment_bar_constructed;
 
 	g_object_class_install_property (
 		object_class,
@@ -534,22 +536,22 @@ e_mail_attachment_bar_class_init (EMailAttachmentBarClass *class)
 }
 
 static void
-e_mail_attachment_bar_interface_init (EAttachmentViewInterface *interface)
+e_attachment_bar_interface_init (EAttachmentViewInterface *interface)
 {
-	interface->get_private = mail_attachment_bar_get_private;
-	interface->get_store = mail_attachment_bar_get_store;
-	interface->get_path_at_pos = mail_attachment_bar_get_path_at_pos;
-	interface->get_selected_paths = mail_attachment_bar_get_selected_paths;
-	interface->path_is_selected = mail_attachment_bar_path_is_selected;
-	interface->select_path = mail_attachment_bar_select_path;
-	interface->unselect_path = mail_attachment_bar_unselect_path;
-	interface->select_all = mail_attachment_bar_select_all;
-	interface->unselect_all = mail_attachment_bar_unselect_all;
-	interface->update_actions = mail_attachment_bar_update_actions;
+	interface->get_private = attachment_bar_get_private;
+	interface->get_store = attachment_bar_get_store;
+	interface->get_path_at_pos = attachment_bar_get_path_at_pos;
+	interface->get_selected_paths = attachment_bar_get_selected_paths;
+	interface->path_is_selected = attachment_bar_path_is_selected;
+	interface->select_path = attachment_bar_select_path;
+	interface->unselect_path = attachment_bar_unselect_path;
+	interface->select_all = attachment_bar_select_all;
+	interface->unselect_all = attachment_bar_unselect_all;
+	interface->update_actions = attachment_bar_update_actions;
 }
 
 static void
-e_mail_attachment_bar_init (EMailAttachmentBar *bar)
+e_attachment_bar_init (EAttachmentBar *bar)
 {
 	EAttachmentView *view;
 	GtkSizeGroup *size_group;
@@ -557,7 +559,7 @@ e_mail_attachment_bar_init (EMailAttachmentBar *bar)
 	GtkWidget *widget;
 	GtkAction *action;
 
-	bar->priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (bar);
+	bar->priv = E_ATTACHMENT_BAR_GET_PRIVATE (bar);
 
 	gtk_box_set_spacing (GTK_BOX (bar), 6);
 
@@ -685,32 +687,32 @@ e_mail_attachment_bar_init (EMailAttachmentBar *bar)
 }
 
 GtkWidget *
-e_mail_attachment_bar_new (EAttachmentStore *store)
+e_attachment_bar_new (EAttachmentStore *store)
 {
 	g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), NULL);
 
 	return g_object_new (
-		E_TYPE_MAIL_ATTACHMENT_BAR,
+		E_TYPE_ATTACHMENT_BAR,
 		"editable", FALSE,
 		"store", store, NULL);
 }
 
 gint
-e_mail_attachment_bar_get_active_view (EMailAttachmentBar *bar)
+e_attachment_bar_get_active_view (EAttachmentBar *bar)
 {
-	g_return_val_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar), 0);
+	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), 0);
 
 	return bar->priv->active_view;
 }
 
 void
-e_mail_attachment_bar_set_active_view (EMailAttachmentBar *bar,
-                                       gint active_view)
+e_attachment_bar_set_active_view (EAttachmentBar *bar,
+                                  gint active_view)
 {
 	EAttachmentView *source;
 	EAttachmentView *target;
 
-	g_return_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar));
+	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
 	g_return_if_fail (active_view >= 0 && active_view < NUM_VIEWS);
 
 	if (active_view == bar->priv->active_view)
@@ -744,18 +746,18 @@ e_mail_attachment_bar_set_active_view (EMailAttachmentBar *bar,
 }
 
 gboolean
-e_mail_attachment_bar_get_expanded (EMailAttachmentBar *bar)
+e_attachment_bar_get_expanded (EAttachmentBar *bar)
 {
-	g_return_val_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar), FALSE);
+	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), FALSE);
 
 	return bar->priv->expanded;
 }
 
 void
-e_mail_attachment_bar_set_expanded (EMailAttachmentBar *bar,
+e_attachment_bar_set_expanded (EAttachmentBar *bar,
                                     gboolean expanded)
 {
-	g_return_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar));
+	g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
 
 	bar->priv->expanded = expanded;
 
@@ -763,9 +765,9 @@ e_mail_attachment_bar_set_expanded (EMailAttachmentBar *bar,
 }
 
 EAttachmentStore *
-e_mail_attachment_bar_get_store (EMailAttachmentBar *bar)
+e_attachment_bar_get_store (EAttachmentBar *bar)
 {
-	g_return_val_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar), NULL);
+	g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
 
 	return E_ATTACHMENT_STORE (bar->priv->model);
 }
diff --git a/widgets/misc/e-attachment-bar.h b/widgets/misc/e-attachment-bar.h
new file mode 100644
index 0000000..9f40973
--- /dev/null
+++ b/widgets/misc/e-attachment-bar.h
@@ -0,0 +1,79 @@
+/*
+ * e-attachment-bar.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ATTACHMENT_BAR_H
+#define E_ATTACHMENT_BAR_H
+
+#include <gtk/gtk.h>
+#include <misc/e-attachment-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT_BAR \
+	(e_attachment_bar_get_type ())
+#define E_ATTACHMENT_BAR(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBar))
+#define E_ATTACHMENT_BAR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass))
+#define E_IS_ATTACHMENT_BAR(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_ATTACHMENT_BAR))
+#define E_IS_ATTACHMENT_BAR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_ATTACHMENT_BAR))
+#define E_ATTACHMENT_BAR_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachmentBar EAttachmentBar;
+typedef struct _EAttachmentBarClass EAttachmentBarClass;
+typedef struct _EAttachmentBarPrivate EAttachmentBarPrivate;
+
+struct _EAttachmentBar {
+	GtkVBox parent;
+	EAttachmentBarPrivate *priv;
+};
+
+struct _EAttachmentBarClass {
+	GtkVBoxClass parent_class;
+};
+
+GType		e_attachment_bar_get_type	(void);
+GtkWidget *	e_attachment_bar_new		(EAttachmentStore *store);
+gint		e_attachment_bar_get_active_view
+						(EAttachmentBar *bar);
+void		e_attachment_bar_set_active_view
+						(EAttachmentBar *bar,
+						 gint active_view);
+gboolean	e_attachment_bar_get_expanded
+						(EAttachmentBar *bar);
+void		e_attachment_bar_set_expanded
+						(EAttachmentBar *bar,
+						 gboolean expanded);
+EAttachmentStore *
+		e_attachment_bar_get_store	(EAttachmentBar *bar);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_BAR_H */
diff --git a/widgets/misc/e-attachment-button.c b/widgets/misc/e-attachment-button.c
index 0d46807..d3aa4a6 100644
--- a/widgets/misc/e-attachment-button.c
+++ b/widgets/misc/e-attachment-button.c
@@ -701,9 +701,10 @@ e_attachment_button_set_view (EAttachmentButton *button,
 
 	g_return_if_fail (button->priv->view == NULL);
 
+	g_object_ref (view);
 	if (button->priv->view)
 		g_object_unref (button->priv->view);
-	button->priv->view = g_object_ref (view);
+	button->priv->view = view;
 
 	popup_menu = e_attachment_view_get_popup_menu (view);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]