Edit Email

This example demonstrates the standard open-edit-save pipeline with Email documents, using different options on every step.

Introduction

There is a group of Email file formats, which usually are intended for storing individual mail letters, or contact data, personal information, calendar and so on. There are plenty of them, because almost every email program uses its own set of such formats.

From its emergence the GroupDocs.Editor for .NET had no support for editing the such documents in Email formats. But starting from the version 22.7 we finally released this possibility! And this article explains in detail how to edit different Email files, because due to their nature their editing differs from editing common text documents.

Loading

Loding of the Email documents is usual and the same as for other formats. Like with text, XPS and e-Book formats, and unlike the PDF and Office formats, there is no loading options for the Email documents — just specify a path to the file or a byte stream with the document content in the constructor of the GroupDocs.Editor.Editor class and that’s all.

Code example below demonstrates loading a single EML file to the Editor instance through the file path and byte stream.

const string emlFilename = "Attachments.eml";
string emlInputPath = System.IO.Path.Combine(Common.TestHelper.EmailFolder, emlFilename);

using (FileStream emlStream = File.OpenRead(emlInputPath))
using (Editor editorFromPath = new Editor(emlInputPath))//from the path
using (Editor editorFromStream = new Editor(emlStream))//from the stream
{
	//Here two Editor instances can separately work with one file
}

Editing

Like for all other formats, there is a special EmailEditOptions class for adjusting editing of the Email documents. Instance of this class should be specified in the Editor.Edit(IEditOptions editOptions) method. And, like for all other formats, it is possible to use a parameterless overload of the Editor.Edit() — in this case, if Email document was loaded to the Editor instance, the GroupDocs.Editor will automatically apply the default EmailEditOptions.

EmailEditOptions class has only one member — a MailMessageOutput property of a MailMessageOutput type. MailMessageOutput is a flagged enum that controls, which parts of the mail message should be delivered to the output EditableDocument and then to the emitted HTML. The MailMessageOutput enum has both atomic values that are responsible for a single part of the mail message, as well as combined values, like Common and All. It is allowed to use not only these combined values, but any user-defined combination of atomic values is acceptable. For example, it is possible to create a combination Subject | Date | To | Cc | Bcc | From, which processes only a metadata, but not the body and attachments list.

It is important to mention that currently the GroupDocs.Editor cannot process the content of the attachments, it can only display a list of attachment names. So the MailMessageOutput.Attachments flag, when specified, emits a list of attachment names, if they are present in the mail message.

Code example below shows adjusting of the MailMessageOutput and generating two different EditableDocument for editing from a single input Email document.

//0. Prepare a sample file
const string emlFilename = "Attachments.eml";
string emlInputPath = System.IO.Path.Combine(Common.TestHelper.EmailFolder, emlFilename);

//1. Load to the Editor class
Editor editor = new Editor(emlInputPath);

//2. Create 1st edit options with only metadata
Options.EmailEditOptions editOptionsMetadata = new EmailEditOptions(MailMessageOutput.Subject | MailMessageOutput.From | MailMessageOutput.To | MailMessageOutput.Cc | MailMessageOutput.Bcc | MailMessageOutput.Date);

//2. Create 2nd edit options with only subject, body and attachments list
Options.EmailEditOptions editOptionsBody = new EmailEditOptions(MailMessageOutput.Subject | MailMessageOutput.Body | MailMessageOutput.Attachments);

//3. Generate two different EditableDocument with these options from single input "Attachments.eml"
EditableDocument onlyMetadata = editor.Edit(editOptionsMetadata);
EditableDocument onlyBody = editor.Edit(editOptionsBody);

//4. Then emit HTML/CSS and send to the WYSIWYG-editor on the client-side

Saving

Saving the edited Email documents in general follows the same principles, like for other document formats, but with several distinctions. As usual, after obtaining an edited HTML-content from the client-side WYSIWYG-editor an instance of the EditableDocument should be created, and then need to pass it to the GroupDocs.Editor.Editor.Save() method.

Like for all other formats, during saving, along with the EditableDocument and a path or a stream, an inheritor of the ISaveOptions interface should be specified, and for email documents it is a EmailSaveOptions class. Like the previously described EmailEditOptions, this class has only one member — a MailMessageOutput property of a MailMessageOutput type. The only distinction between this MailMessageOutput property in EmailEditOptions and EmailSaveOptions is that in the first case the MailMessageOutput property controls, which parts of the mail message will be processed while generating EditableDocument from the input Email file, while in the second case the MailMessageOutput property controls, which parts of the mail message will be processed while generating output Email file from EditableDocument, obtained after editing. So it is possible, for example, send to the WYSIWYG-editor a full mail message with 100% all content, but generate an output file only with a Subject and Body content, for example.

Email format family consists of many different formats, but the EmailSaveOptions does not allow to specify the format for the output document — it automatically be the same, as the format of the original Email document, loaded into the GroupDocs.Editor.Editor class. So, for example, if you loaded the MSG file, then the GroupDocs.Editor.Editor.Save() method will also generate the MSG file, and no matter which file extension you specify.

Code example below shows full load-edit-save pipeline for the Email documents. It loads a document, makes it editable with MailMessageOutput.All combined flag, and then generates to output Email documents: first one is saved to the file with MailMessageOutput.Common, while second is saved to the stream with customly created combined flag.

//0. Prepare a sample file
const string msgFilename = "ComplexExample.msg";
string msgInputPath = System.IO.Path.Combine(Common.TestHelper.EmailFolder, msgFilename);

//1. Load to the Editor class
Editor msgEditor = new Editor(msgInputPath);

//2. Create edit options with all content
Options.EmailEditOptions editOptions = new EmailEditOptions(MailMessageOutput.All);

//3. Generate an editable document
EditableDocument originalDoc = msgEditor.Edit(editOptions);

//4. Emit HTML from EditableDocument, send it to the client-side, edit it there in WYSIWYG-editor (omitted here)
string savedHtmlContent = originalDoc.GetEmbeddedHtml();

//5. Obtain edited content from the client-side and generate a new EditableDocument from it (omitted here)
EditableDocument editedDoc = EditableDocument.FromMarkup(savedHtmlContent, null);

//6. Create 1st save options
EmailSaveOptions saveOptions1 = new EmailSaveOptions(MailMessageOutput.Common);

//7. Create 2nd save options
EmailSaveOptions saveOptions2 = new EmailSaveOptions(MailMessageOutput.Body | MailMessageOutput.Attachments);

//8. Generate and save 1st output MSG to the file
string outputMsgPath = System.IO.Path.Combine(Common.TestHelper.OutputFolder, "OutputFile.msg");
msgEditor.Save(editedDoc, outputMsgPath, saveOptions1);

//9. Generate and save 2nd output MSG to the stream
Stream outputMsgStream = File.Create(Path.Combine(Common.TestHelper.OutputFolder, "OutputStream.msg"));
msgEditor.Save(editedDoc, outputMsgStream, saveOptions2);

//10. Dispose all resources
outputMsgStream.Dispose();
editedDoc.Dispose();
originalDoc.Dispose();
msgEditor.Dispose();

Obtaining Email document info

Article Extracting document metainfo describes the GetDocumentInfo() method, that allows to detect the document format and extract its metadata without editing it. Actually, after adding Email support to the GroupDocs.Editor, this mechanism also works with Email documents.

When the GetDocumentInfo() method is called for the Editor class instance that is loaded with an Email document, the method will return a GroupDocs.Editor.Metadata.EmailDocumentInfo instance — it is a common class for all Email formats like EML, EMLX, MSG and so on.

As all IDocumentInfo implementations, it has four properties:

  1. Format property of Formats.EmailFormats type. It indicates the specific format of the given Email document.
  2. PageCount property of integer (Int32) type. It always return 1, because email documents don’t have paged view
  3. Size property of a long integer (Int64) type. Returns a file size in bytes.
  4. IsEncrypted property of a Boolean type. Because email documents cannot be encrypted with password, this property always returns false.

Code example below displays extracting document info from three different Email documents of different formats. Source code is represented as a unit-test, written with NUnit framework.

const string emlFilename = "Attachments.eml";
string emlInputPath = System.IO.Path.Combine(Common.TestHelper.EmailFolder, emlFilename);

const string msgFilename = "ComplexExample.msg";
string msgInputPath = System.IO.Path.Combine(Common.TestHelper.EmailFolder, msgFilename);

const string pstFilename = "PersonalStorage.pst";
string pstInputPath = System.IO.Path.Combine(Common.TestHelper.EmailFolder, pstFilename);

Editor emlEditor = new Editor(emlInputPath);
Editor msgEditor = new Editor(msgInputPath);
Editor pstEditor = new Editor(pstInputPath);

IDocumentInfo emlDocInfo = emlEditor.GetDocumentInfo(null);
IDocumentInfo msgDocInfo = msgEditor.GetDocumentInfo(null);
IDocumentInfo pstDocInfo = pstEditor.GetDocumentInfo(null);

Assert.IsTrue(emlDocInfo is EmailDocumentInfo);
Assert.IsTrue(msgDocInfo is EmailDocumentInfo);
Assert.IsTrue(pstDocInfo is EmailDocumentInfo);

Assert.AreEqual(GroupDocs.Editor.Formats.EmailFormats.Eml, emlDocInfo.Format);
Assert.AreEqual(GroupDocs.Editor.Formats.EmailFormats.Msg, msgDocInfo.Format);
Assert.AreEqual(GroupDocs.Editor.Formats.EmailFormats.Pst, pstDocInfo.Format);

emlEditor.Dispose();
msgEditor.Dispose();
pstEditor.Dispose();