# Converting E-mail Messages and Saved Web Pages

PD4ML reads e-mail messages (`.eml`) and web pages saved as a single file (`.mht`, `.mhtml`) as well as HTML, and writes them to any output format.

```java
PD4ML pd4ml = new PD4ML();
pd4ml.readHTML(new File("message.eml").toURI().toURL());   // or page.mht
pd4ml.writePDF(new FileOutputStream("message.pdf"));
```

`readHTML(...)` recognizes these files, from a URL or a stream: by the `.eml`, `.mht` or `.mhtml` ending of the URL path, and otherwise by how the content starts. Input counts as a message or a saved page if all its lines up to the first empty one are headers, with `Content-Type` or `MIME-Version` among them, or `From` together with `Date`, `Received` or `Message-ID`. A saved page is told from a message by `Snapshot-Content-Location`, by a `From` with "Saved by", or by `multipart/related` with no `From` and `To`.

If you know what the input is, say so; this is the way to go for mail from outside your control:

```java
pd4ml.readEML(inputStream);    // or readEML(url)
pd4ml.readMHT(inputStream);    // or readMHT(url)
```

Recognition is a judgment on the first lines of the input. A file made to escape it is read as ordinary HTML, without the protection described below.

`Pd4Cmd` takes the same files as its source:

```
java -Djava.awt.headless=true -jar pd4ml.jar "file:message.eml" 800 A4 -out message.pdf
```

{% hint style="version" %}
Available from **PD4ML v4.2.0**, with both layout engines.
{% endhint %}

## What ends up in the document

**E-mail message**

- A block with From, Date, To, Cc and Subject, and the names and sizes of the attachments. Bcc is left out.
- The body: the HTML version if the message has one, otherwise the plain text. Parts of a `multipart/mixed` message follow each other.
- Images the message embeds (`cid:` references, in `<img>` and in CSS), and images it carries as inline parts.
- A forwarded message attached to it (`message/rfc822`), after the body, with its own block.

**Saved web page**

- The page, with the images, style sheets and fonts saved in the file, found by `Content-ID` or `Content-Location`, also from inside the style sheets. There is no block of headers.
- Links that were relative on the original page lead to where they led there, as the page's original `http` or `https` location becomes its base.

Subject, or the page's own title if there is none, becomes the title of the document. The charset of each part, encoded headers (RFC 2047, RFC 2231), `base64`, `quoted-printable` and `format=flowed` text are handled, and so is damaged input: bare line feeds, a missing closing boundary, a mislabeled charset.

## The attachments are embedded

The files attached to a message are embedded in the PDF, each next to its name in the block at the top of the document. An attachment comes from the sender, and the PDF hands it on to whoever opens it, executables included.

Signature parts (`smime.p7s`) are not attachments and are left out; images the body displays are not attachments either.

Only PDF has embedded files, and PDF/A-1 and PDF/A-2 do not allow them: these and the other outputs keep the list of names.

A message cannot embed anything else by itself: `<pd4ml:attachment>` and `<pd4ml:include>` tags in its HTML are dropped.

## Resources outside of the file

Of the images, style sheets and fonts a file refers to but does not contain, only those at `https://` locations are loaded. Local files (`<img src="file:/...">`), relative references that the file does not resolve itself and `http://` locations are not.

A remote image in a message tells its sender when and where the message was opened. To change what loads, list the locations with `addAllowedResourceLocation(...)`, which replaces this default. As for any document read from a URL, the location of the file itself must then be on the list, unless you read it from a stream:

```java
pd4ml.addAllowedResourceLocation("https://cdn.example.com/");   // only this server
pd4ml.readEML(new FileInputStream("message.eml"));
```

With `Pd4Cmd`, use `-param pd4ml.allowed.resource.location "https://cdn.example.com/"`.

The list covers everything else PD4ML loads during the conversion too, such as an image in a header you set with `setPageHeader(...)`: allow its location as well, or embed the image as a `data:` URI. Fonts from `useTTF()` are yours and are not affected. See [Restricting Resource Loading for Untrusted HTML](restricting-resource-loading-for-untrusted-html).

## Limitations

- **Frames**: the content of `<iframe>` and `<frame>` elements is not shown, as with HTML input.
- **Scripts do not run**: the page shows as it was saved, without what its scripts would have changed.
- **Word page headers and footers**: a page saved by Word keeps its body; the headers and footers Word stores in parts of their own are not shown.
- **Encrypted messages**: the content of an S/MIME or PGP encrypted message is not decrypted, so there is no body to show.
- **Fonts**: text in scripts the built-in fonts do not cover needs `useTTF(...)`, as with HTML input.
