Repository: jhillyerd/enmime
Pull request #334 (2024-05-03 06:40:20)

Add parser option to disable HTML to Text down conversion

coveralls: 
[![Coverage Status](https://coveralls.io/builds/67282142/badge)](https://coveralls.io/builds/67282142)

coverage: 86.253% (-0.1%) from 86.392%
when pulling **6c9b89ba7cda320f677c9e7ce1afe79763f5ed8a on tvdv:feature/skip-html2text**
into **5139f90613fe9a666ac1f84cd3d8c6cc4924d1aa on jhillyerd:main**.

jhillyerd: Good idea!  Sorry for the slow response, I wanted to rename the option, but then saw we needed tests as well.

Patch:
diff --git a/envelope.go b/envelope.go
index 5c36e6f..bfade4f 100644
--- a/envelope.go
+++ b/envelope.go
@@ -201,11 +201,14 @@ func (p Parser) EnvelopeFromPart(root *Part) (*Envelope, error) {
 		e.Root.addWarning(
 			ErrorPlainTextFromHTML,
 			"Message did not contain a text/plain part")
-		var err error
-		if e.Text, err = html2text.FromString(e.HTML); err != nil {
-			e.Text = "" // Down-conversion shouldn't fail
-			p := e.Root.BreadthMatchFirst(matchHTMLBodyPart)
-			p.addError(ErrorPlainTextFromHTML, "Failed to downconvert HTML: %v", err)
+
+		if !p.disableTextConversion {
+			var err error
+			if e.Text, err = html2text.FromString(e.HTML); err != nil {
+				e.Text = "" // Down-conversion shouldn't fail
+				p := e.Root.BreadthMatchFirst(matchHTMLBodyPart)
+				p.addError(ErrorPlainTextFromHTML, "Failed to downconvert HTML: %v", err)
+			}
 		}
 	}
 
diff --git a/options.go b/options.go
index 0a0175e..b7e6fd2 100644
--- a/options.go
+++ b/options.go
@@ -88,3 +88,15 @@ func (o stripMediaTypeInvalidCharactersOption) apply(p *Parser) {
 func StripMediaTypeInvalidCharacters(stripMediaTypeInvalidCharacters bool) Option {
 	return stripMediaTypeInvalidCharactersOption(stripMediaTypeInvalidCharacters)
 }
+
+type disableTextConversionOption bool
+
+func (o disableTextConversionOption) apply(p *Parser) {
+	p.disableTextConversion = bool(o)
+}
+
+// DisableTextConversion sets the disableTextConversion option. When true, there will be no
+// automated down conversion of HTML to text when a plain/text body is missing.
+func DisableTextConversion(disableTextConversion bool) Option {
+	return disableTextConversionOption(disableTextConversion)
+}
diff --git a/parser.go b/parser.go
index a2bf422..2ca6939 100644
--- a/parser.go
+++ b/parser.go
@@ -26,6 +26,7 @@ type Parser struct {
 	rawContent                      bool
 	customParseMediaType            CustomParseMediaType
 	stripMediaTypeInvalidCharacters bool
+	disableTextConversion           bool
 }
 
 // defaultParser is a Parser with default configuration.


Test patch:
diff --git a/envelope_test.go b/envelope_test.go
index bc19759..bc351e6 100644
--- a/envelope_test.go
+++ b/envelope_test.go
@@ -516,6 +516,51 @@ func TestParseHTMLOnlyInline(t *testing.T) {
 	}
 }
 
+func TestParseHTMLOnlyInlineTextDisabled(t *testing.T) {
+	msg := test.OpenTestData("mail", "html-only-inline.raw")
+
+	parser := enmime.NewParser(enmime.DisableTextConversion(true))
+	e, err := parser.ReadEnvelope(msg)
+	if err != nil {
+		t.Fatal("Failed to parse MIME:", err)
+	}
+
+	if len(e.Errors) == 1 {
+		want := enmime.ErrorPlainTextFromHTML
+		got := e.Errors[0].Name
+		if got != want {
+			t.Errorf("e.Errors[0] got: %v, want: %v", got, want)
+		}
+	} else {
+		t.Errorf("len(e.Errors) got: %v, want: 1", len(e.Errors))
+	}
+
+	if e.Text != "" {
+		t.Errorf("Downconverted Text was %q, should be empty", e.Text)
+	}
+
+	want := ">Test of HTML section<"
+	if !strings.Contains(e.HTML, want) {
+		t.Errorf("HTML: %q should contain %q", e.HTML, want)
+	}
+
+	if len(e.Inlines) != 1 {
+		t.Error("Should one inline, got:", len(e.Inlines))
+	}
+	if len(e.Attachments) > 0 {
+		t.Fatal("Should have no attachments, got:", len(e.Attachments))
+	}
+
+	want = "favicon.png"
+	got := e.Inlines[0].FileName
+	if got != want {
+		t.Error("FileName got:", got, "want:", want)
+	}
+	if !bytes.HasPrefix(e.Inlines[0].Content, []byte{0x89, 'P', 'N', 'G'}) {
+		t.Error("Inline should have correct content")
+	}
+}
+
 func TestParseInlineMultipart(t *testing.T) {
 	msg := test.OpenTestData("mail", "inlinemultipart.raw")
 	e, err := enmime.ReadEnvelope(msg)