MIME mail encoding and decoding package for Go



PkgGoDev Build Status Go Report Card Coverage Status

enmime is a MIME encoding and decoding library for Go, focused on generating and parsing MIME encoded emails. It is being developed in tandem with the Inbucket email service.

enmime includes a fluent interface builder for generating MIME encoded messages, see the wiki for example Builder Usage.

See our Pkg Docs for examples and API usage information.

Development Status

enmime is near production quality: it works but struggles to parse a small percentage of emails. It's possible the API will evolve slightly before the 1.0 release.

See CONTRIBUTING.md for more information.


enmime is written in Go.

enmime is open source software released under the MIT License. The latest version can be found at https://github.com/jhillyerd/enmime

  • feat: add option skip malformed parts

    feat: add option skip malformed parts

    This PR is proposal for the feature which allows to skip parts that can't be parsed. It won't return error, just add them to "problems"

    This can be useful if you need to parse everything what is possible to parse and turned off by default.

    For example, we have emails which have body of the email starting at the beginning of the part (without headers). Currently parser returns error, but it can be beneficial to skip this part.

    Content-Type: multipart/report; report-type=delivery-status;
    Auto-Submitted: auto-generated (failure)
    MIME-Version: 1.0
    The original message was received
    opened by dmytrokasianenko-outreach 14
  • 'slash after first token' when parsing some emails

    'slash after first token' when parsing some emails

    What I did: parsed some mimes

    What I expected: to get parsed object

    What I got: error

    Release or branch I am using: [0.8.2] - 2020-10-10

    (Please attach a sample message if you feel it will help reproduce the issue)

    First of all, thank for the helpful package! But I get error when I parse some mimes: expected slash after first token I parse them like this: enmime.ReadEnvelope(strings.NewReader(mime))

    Can you suggest me please how to avoid this problem ? Below is the example of mime which gives error:

    Return-Path: <[email protected]>
    Delivered-To: [email protected]
    Received: from dcd-15 ([])
    	by dcbackend-15.iol.local with LMTP id wBOnApYfll9gIAUATByfJw
    	for <[email protected]>; Mon, 26 Oct 2020 02:00:06 +0100
    Received: from dcp-33.iol.local ([])
    	by dcd-15 with LMTP id qDyMApYfll/wYgAAkA0XfQ
    	; Mon, 26 Oct 2020 02:00:06 +0100
    Received: from libero.it ([])
    	by dcp-33.iol.local with LMTP id MPfpG5Mfll+4JAEAVzGdtA
    	; Mon, 26 Oct 2020 02:00:06 +0100
    Received: from so254-8.mailgun.net ([])
    	by smtp-07.iol.local with ESMTP
    	id Wqrkk7ui19msRWqrlkdWIE; Mon, 26 Oct 2020 02:00:06 +0100
    X-IOL-DMARC: Dominio libertycomc.com non supporta DMARC
    X-IOL-DKIM: pass con il dominio d=libertycomc.com
    X-IOL-SPF: pass con l'IP;libertycomc.com
    x-libjamoibt: 2601
    Received-SPF: pass
    X-CNFS-Analysis: v=2.4 cv=KPrksHJo c=1 sm=1 tr=0 ts=5f961f96 b=1
     a=9V+36KcF1VtsQasMD0NMeA==:117 a=9V+36KcF1VtsQasMD0NMeA==:17
     a=IkcTkHD0fZMA:10 a=afefHYAZSVUA:10 a=5KLPUuaC_9wA:10 a=swULO2ODAAAA:8
     a=8IFCRQWyzuk3np_0jKQA:9 a=AFaUXfkzamQ7vrcO:21 a=frz4AuCg-hUA:10
     a=QEXdDO2ut3YA:10 a=VPRn9Uh7xMAA:10 a=PCWqMptlEwVzXmuMJime:22
    Authentication-Results: smtp-07.iol.local;
    	dkim=pass header.d=libertycomc.com header.b=TfJm39aZ
    DKIM-Signature: a=rsa-sha256; v=1; c=relaxed/relaxed; d=libertycomc.com; q=dns/txt;
     s=krs; t=1603674005; h=Content-Transfer-Encoding: Mime-Version:
     Content-Type: Subject: From: To: Message-Id: Sender: Date;
     bh=faAL8rCmOc2K1K3IP+7qQSPKUakoqX/vM3mtikLFN0I=; b=TfJm39aZ1YvR3TVhRaf5BOcqO6N5ED/Kch55jvSrHK95UTu6KuKpHzAamCG9yJ4ithTOrC53
    X-Mailgun-Sid: WyJkMDIzMiIsICJnZW5lcmFsLmNvbnN0cnVjdGlvbkBsaWJlcm8uaXQiLCAiOTQxNWQyIl0=
    Received: by luna.sendgrid.net with HTTP; Mon, 26 Oct 2020 01:00:04 +0000
    Date: Mon, 26 Oct 2020 01:00:04 +0000
    Sender: [email protected]
    Message-Id: <[email protected]>
    To: [email protected]
    From: LibertyComc <[email protected]>
    Subject: =?utf-8?q?Il_tuo_contratto_di_assistenza_LibertyOnCall_Base_?=
    Content-Type: text/html; charset="utf-8"
    Mime-Version: 1.0
    Content-Transfer-Encoding: quoted-printable
    X-CMAE-Envelope: MS4xfNvTvUqy52h0PkJMOD3B7ZoQxPkRJk/JMo2kfmIlF7l6O3wP4UkVrLsi6TBS/nxvz1zrbHrMhIiA9gTN2dELm5hM39y496Dn/14V6nFuqnxTAsnInGBo
    <!-- BEGIN: main --><!DOCTYPE html>
    <html lang=3D"it">
       <meta charset=3D"UTF-8">
       <title>Il tuo contratto di assistenza LibertyOnCall Base =C3=A8 scaduto<=
       <style type=3D"text/css">
          body {
             font-family: Verdana, Arial, Helvetica, sans-serif;
             font-size: 11px
       <div style=3D"width:100%; background-color:#f7f7f4; padding-bottom:30px;=
     padding-top:10px; margin:0">
          <div style=3D"width:640px; margin-left:auto; margin-right: auto; back=
    ground-color:#ffffff;box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rg=
             <div style=3D"padding:10px; margin:5px 0 0 0; border-bottom:1px so=
    lid #dddddd; font-size:11px">
                <img src=3D"http://www.libertycomc.com/assets/email/logo_lib=
             <div style=3D"color:#333333; font-weight:bold; background-color:#e=
    fefef; padding:5px 10px 8px 10px; font-size:15px; font-family:Arial,Verdana=
                Il tuo contratto di assistenza LibertyOnCall Base =C3=A8 scaduto
             <div style=3D"color:#333333; padding:10px 10px 10px 10px; font-siz=
    e:15px; font-family:Arial,Verdana,sans-serif">
    <table width=3D"100%" border=3D"0" cellspacing=3D"2" cellpadding=3D"5">
    		<td align=3D"center" bgcolor=3D"#FF3F3F">
    			<span style=3D"color: cornsilk; font-weight: bold"> Il tuo contratto di =
    assistenza =C3=A8 scaduto </span>
    			Gentile <strong>General C1C</strong>, <b=
    			dai nostri archivi risulta che il contratto di assistenza
    			<strong>LibertyOnCall Base</strong> da te sottoscritto =C3=A8 scaduto il=
     giorno <strong>23/10/2020</strong>.<br>
    			Per poter continuare ad usufruire del servizio ti invitiamo a rinnovarlo=
     per un altro anno. <br>
    			<div align=3D"center" style=3D"margin:10px">
    				<a style=3D"text-decoration:none; font-weight: bold; background-color:#=
    eee; color:#004276; border-radius: 4px; padding:8px; border:1px solid #bbbb=
    bb" href=3D"http://legacy.libertycomc.com/negozio/quickbuy.php?ql=3D7B65=
    301413CC604233EEE6B61139D18A8B94461795">Clicca per rinnovare</a>
             <div style=3D"text-align:center; background-color:#f6f6f6; padding=
    :10px; margin:5px 0 5px 0; border-top:1px solid #dddddd; font-size:10px;  f=
    ont-family:Arial,Verdana,sans-serif">&copy;2020 Liberty Line srl</div>
    <img width=3D"1px" height=3D"1px" alt=3D"" src=3D"http://email.libertycomme=
    </html><!-- END: main -->
    bug decoding 
    opened by miknaz 14
  • Requaos/nontermboundry


    Had an issue where the boundary was not terminated, and I saw some tests around this but my case fell through the cracks. I refactored the Read() function to go one byte at a time and only peek the length of the fullBoundary. (edited) There was a case where the boundary was being detected 2x chars early for whitespace at the head, resolved in b6a4d4e

    opened by requaos 13
  • boundary_test failures under Go 1.12.1

    boundary_test failures under Go 1.12.1

    What I did:

    Run unit tests with go version go1.12.1 linux/amd64

    What I expected:


    What I got:

    --- FAIL: TestBoundaryReader (0.00s)
        boundary_test.go:95: Rest of reader:
            got: "\n--STOPHERE\r\nafter", want: "\r\n--STOPHERE\r\nafter"
        boundary_test.go:95: Rest of reader:
            got: "\n--STOPHERE\t\r\nafter", want: "\r\n--STOPHERE\t\r\nafter"
        boundary_test.go:95: Rest of reader:
            got: "\n--STOPHERE--\r\nafter", want: "\r\n--STOPHERE--\r\nafter"
        boundary_test.go:95: Rest of reader:
            got: "\n--STOPHERE \t\r\nafter", want: "\r\n--STOPHERE \t\r\nafter"
        boundary_test.go:95: Rest of reader:
            got: "\n--STOPHERE--\t \r\nafter", want: "\r\n--STOPHERE--\t \r\nafter"
        boundary_test.go:95: Rest of reader:
            got: "\n--STOPHERE--\r\nafter", want: "\r\n--STOPHERE--\r\nafter"
        boundary_test.go:95: Rest of reader:
            got: "\n--STOPHERE--\r\nafter", want: "\r\n--STOPHERE--\r\nafter"
    FAIL	github.com/jhillyerd/enmime	1.556s

    Release or branch I am using: develop


    opened by jhillyerd 12
  • Access all headers from Envelope

    Access all headers from Envelope

    With the later changes, the headers field of the Envelope has been made private. I have need of all headers in the email and there does not seem to be a way of doing this without knowing ahead of time what they are, and using the GetHeader method.

    Do you have a recommended way of doing this, ie perhaps a new HeaderKeys method, make headers public, or a new GetRawHeader method, or perhaps there is something I'm missing?

    opened by ts2909 11
  • Fix for certain charset duplicate params error

    Fix for certain charset duplicate params error

    If a duplicate param is present then parsing of the entire email fails. This fix handles a misplaced ";" in content-type. It also handles empty name in content-type. I have also added a unit test for this scenario.

    opened by deepakprabhakara 9
  • Bug in parsing logic of readHeader

    Bug in parsing logic of readHeader

    If the header contains fields like "Dkim-Signature" or "Domainkey-Signature" which contain a 'Content-Type:' inside the value then Content-Type header field is parsed wrongly as 'List-Unsubscribe; b=oCvFiVQEh8Fqkfnk9yJ2llkWAnsRxQr8Xf10SjcXK2wrzCXtizroaBbi0FZ7XbHd9fFz03 9UcQ7Vc1EUZ8pAHMG98BRjVaUNuEl2Eqle+NoKi+zRA023xULkCmWzWalclNB/FI5YTEQCpl JBE4+6LWrtWlorhybEDjvi4chJzc0=' instead of 'multipart/alternative; boundary=mimepart_583f950f96b48_6afcdf1038924a'.

    Example headers in the email:- "headers": { "Authentication-Results": "mx.google.com; dkim=pass [email protected]; spf=pass (google.com: domain of [email protected] designates as permitted sender) [email protected]pp.com", "Content-Type": "multipart/alternative; boundary=mimepart_583f950f96b48_6afcdf1038924a", "Delivered-To": "[email protected]", "Dkim-Signature": "a=rsa-sha256; v=1; c=relaxed/relaxed; d=papertrailapp.com; q=dns/txt; s=krs; t=1480561936; h=List-Unsubscribe: Content-Type: Mime-Version: Subject: Message-Id: To: From: Date: Sender; bh=Ypk2VpJetOH0wE/ecQUh9usmggXKCYSph2kozqlVh78=; b=oBgHqQb5gL9P21CVXgOUN06ByZHE4Znxnyp3JsIePEzsMDF+Z4nuzKl9CeQA1gv6B3v329Tr W6yRYEXPBPANr2EWcbK9gPUjT33SLckZlvFbaIeEv4/bdCrcr0V7CTBQzMLhXmDuv8xth427 FFlyn2Zy0dWTMFd3UUvp64QrTYc=", "Domainkey-Signature": "a=rsa-sha1; c=nofws; d=papertrailapp.com; s=krs; q=dns; h=Sender: Date: From: To: Message-Id: Subject: Mime-Version: Content-Type: List-Unsubscribe; b=oCvFiVQEh8Fqkfnk9yJ2llkWAnsRxQr8Xf10SjcXK2wrzCXtizroaBbi0FZ7XbHd9fFz03 9UcQ7Vc1EUZ8pAHMG98BRjVaUNuEl2Eqle+NoKi+zRA023xULkCmWzWalclNB/FI5YTEQCpl JBE4+6LWrtWlorhybEDjvi4chJzc0=", "List-Unsubscribe": "https://papertrailapp.com/account", "Message-Id": "[email protected]", "Mime-Version": "1.0", "Received": "by with SMTP id y205csp655646vkd; Wed, 30 Nov 2016 19:12:17 -0800 (PST)\nfrom smtp-out.papertrailapp.com (smtp-out.papertrailapp.com. []) by mx.google.com with ESMTPS id d12si49552199iof.62.2016. for [email protected] (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 Nov 2016 19:12:16 -0800 (PST)\nfrom papertrailapp.com (pt02rw04.papertrailapp.com []) by mxa.mailgun.org with ESMTP id 583f9510.7f4fa0643298-smtp-out-n03; Thu, 01 Dec 2016 03:12:16 -0000 (UTC)", "Received-Spf": "pass (google.com: domain of [email protected] designates as permitted sender) client-ip=;", "Return-Path": "[email protected]", "Sender": "[email protected]", "X-GM-MSGID": "158b85e4ae57c1ba", "X-GM-THRID": "158b85e4ae57c1ba", "X-Mailgun-Sending-Ip": "", "X-Mailgun-Sid": "WyI3YjEyNCIsICJkZWVwYWtAcmVkc2lmdC5pbyIsICIxOTEwOTkiXQ==", "X-Received": "by with SMTP id u5mr31628139itb.45.1480561936981; Wed, 30 Nov 2016 19:12:16 -0800 (PST)", "X-Report-Abuse-To": "[email protected]" }

    opened by deepakprabhakara 9
  • Maximal number of errors recorded in Part limited

    Maximal number of errors recorded in Part limited


    I use enmime to parse emails in my service. It happened that instead of valid mime structure, client sent several MBs of base64 data as input. In such case, enmime consumes a lot of memory (several GBs). It's because readHeader function adds many many warnings in order to "Attempt to detect and repair a non-indented continuation of previous line" as comment says.

    In the end, readHeader calls ReadMIMEHeader, which doesn't find valid MIME structure and fails with error and all these warnings are freed. However the memory peak remains and can lead to swapping.

    To make it more robust, I'm adding a MaxPartErrors global public variable, which does not allow to record more than limit errors in one part. Default value is 1000 in my PR, but it can be also 0 if you desire, which means no limit and thus there will be no change in current behavior.

    Best regards Pavel

    opened by pavelbazika 8
  • ReadEnvelope panic

    ReadEnvelope panic

    What I did:

    package main
    import (
    func main() {
    	r, err := os.Open("./test_files/071.eml")
    	if err != nil {
    	env, err := enmime.ReadEnvelope(r)
    	if err != nil {

    What I expected: success. What I got:

    panic: runtime error: index out of range [4096] with length 4096

    Release or branch I am using: V0.9.2 (Please attach a sample message if you feel it will help reproduce the issue)

    goroutine 1 [running]:
            C:/Users/John Li/go/pkg/mod/github.com/jhillyerd/[email protected]/internal/coding/quotedprint.go:50
    github.com/jhillyerd/enmime/internal/coding.(*QPCleaner).Read(0xc00007f080, {0xc00019c000, 0x1000, 0xbdd0a7})
            C:/Users/John Li/go/pkg/mod/github.com/jhillyerd/[email protected]/internal/coding/quotedprint.go:125 +0xf31
    opened by ly020044 8
  • Formatted header breaks email readability when received on mail user agent

    Formatted header breaks email readability when received on mail user agent

    Release or branch I am using: v0.8.1

    Parsing formatted headers using the library leads to an email that is no longer correctly parsable by mail user agents. A sample header is attached here for readability with the original formatting.

    This has been introduced in this commit, function readHeader in header.go file, lines 107-113.

    What is obtained after parsing the incoming email: 0.00 BSF_BESS_OUTBOUND META: BESS Outbound 0.00 HTML_MESSAGE BODY: HTML included in message 0.01 SUBJ_ALL_CAPS META: Subject is all capitals 0.20 BSF_SC0_SAXXX META: Custom Rule BSF_SC0_SAXXX X-Bess-Outbound-Spam-Report: Code version 3.2, rules version [from scanhost.whatever.wherever.com] Rule breakdown below pts rule name description ---- ---------------------- --------------------------------

    Which breaks parsing and displaying.

    opened by pacellig 8
  • Handle very empty MIME part

    Handle very empty MIME part

    When one MIME boundary immediately follows another, treat it as an empty part.

    This comes from an issue I saw in a production environment where there was an email where a MIME part delimiter was immediately followed by a terminator. Like this:

    Content-type: multipart/mixed; boundary="the-boundary"
    Content-type: text/plain
    Some content.
    opened by dcormier 8
  • Should enmime detect HTML format and convert to text in this case?

    Should enmime detect HTML format and convert to text in this case?

    Dear all,

    I recently got an email in such format, main content-type is multipart/mixed, one of the part in body is text/plain with Content-Transfer-Encoding: quoted-printable, it contains HTML code and base64 encoded image. enmime doesn't convert html to text, and the encoded image is included in result too.

    Question: should enmime detect HTML format and convert it to text in such case?

    MIME-Version: 1.0
    ... [omit other normal email headers here] ...
    Content-Type: multipart/mixed; 
    Content-Transfer-Encoding: quoted-printable
    Content-Type: text/plain; charset=UTF-8
    <div style=3D"caret-color: rgba(0, 0, 0, 0.847); color: rg=
    ba(0, 0, 0, 0.847); font-size: 12px;"><img src=3D"data:image/jpeg;base64,/9=
    ... [omit long base64 lines] ...
    discussion decoding 
    opened by iredmail 2
  • Feature request: ordered headers

    Feature request: ordered headers

    Dear @jhillyerd,

    Mail headers stored in header attribute is unordered (the underlying type of *textproto.MIMEHeader is map[string][]string): https://github.com/jhillyerd/enmime/blob/5cd80012a864d71e2fe03bae39079080a4896160/envelope.go#L28

    I wonder whether you're willing to accept PR to make it an ordered map instead. Since header is an internal attribute, i expect no breaking changes will be introduced.

    Ordered headers is very useful when you just modified part of mail body and want to keep the order.

    enhancement decoding 
    opened by iredmail 1
  • mime-extractor: write subject and text

    mime-extractor: write subject and text

    It would be nice to write message text to files. Same as in this patch.

    index 2313bc4..974e0ec 100644
    --- a/cmd/mime-extractor/mime-extractor.go
    +++ b/cmd/mime-extractor/mime-extractor.go
    @@ -81,6 +81,29 @@ func (ex *extractor) extract(file, dir string) int {
            // Write errOut attachments
            fmt.Fprintf(ex.errOut, "\nExtracting attachments into %s...", dir)
    +       // Write Subject
    +       newFileName := filepath.Join(dir, ".subject")
    +       err = ex.fileWrite(newFileName, []byte(e.GetHeader("Subject")), 0644)
    +       if err != nil {
    +               fmt.Fprintf(ex.stdOut, "Error writing file %q: %v\n", newFileName, err)
    +       }
    +       // Write TEXT
    +       newFileName = filepath.Join(dir, ".text")
    +       err = ex.fileWrite(newFileName, []byte(e.Text), 0644)
    +       if err != nil {
    +               fmt.Fprintf(ex.stdOut, "Error writing file %q: %v\n", newFileName, err)
    +       }
    +       // Write HTML
    +       newFileName = filepath.Join(dir, ".html")
    +       err = ex.fileWrite(newFileName, []byte(e.HTML), 0644)
    +       if err != nil {
    +               fmt.Fprintf(ex.stdOut, "Error writing file %q: %v\n", newFileName, err)
    +       }
    +       // Write attachments
            for _, a := range e.Attachments {
                    newFileName := filepath.Join(dir, a.FileName)
                    err = ex.fileWrite(newFileName, a.Content, 0644)

    I use this patch. May be other users need something the same...

    opened by c0de9en 0
  • Wrong parsing of text/html with boundary

    Wrong parsing of text/html with boundary

    What I did: Parsing a message which has text/html part but it contains also "boundary" marker. I know, this is an strange case but we have the messages with it.

    IMO, https://github.com/jhillyerd/enmime/blob/1f2f4b04f3877165dda8357742c6d00ae09a1652/part.go#L404 we could check if the content type with "detectTextHeader", wdyt?

    Or reporting it with error and providing content to the part. IMO the part is wrongly classified.

    What I expected: To have HTML text loaded from that part.

    What I got: Empty string + I cant access the body of that part :(

    Release or branch I am using: master (Please attach a sample message if you feel it will help reproduce the issue)

    Content-Type: text/html;
    Content-Transfer-Encoding: quoted-printable
    enhancement good first issue decoding 
    opened by kadukf-outreach 1
  • Ability to turn off extra processings, e.g. html2text.FromString

    Ability to turn off extra processings, e.g. html2text.FromString

    What I did: Parsing a mime without text/plain part. Field Text on the envelope returns a text using html2text converter. This processing is consuming memory as well as CPU. Would it be possible, e.g. using options, to manage this extra work? By default ON, but having a possiblity to turn it OFF but still reporting ErrorPlainTextFromHTML.

    What I expected: Empty text.

    What I got: Text converted by html2text.

    Release or branch I am using: master

    (Please attach a sample message if you feel it will help reproduce the issue)

    enhancement decoding 
    opened by kadukf-outreach 1
  • v0.10.1(Sep 18, 2022)

  • v0.10.0(Jul 21, 2022)


    • Support for parser options! (#248)
    • Option to skip parsing of malformed parts (#248)
    • Envelope.Date() method for parsing date (#253)
    • Option to handle missing multipart boundaries (#257)


    • Remove trailing HTML tags (#252)
    • Buffer overrun in quoted-printable (#254)
    • Corrected quoted-printable equals counting (#255)
    • Improve splitting inside quoted text (#256)
    Source code(tar.gz)
    Source code(zip)
  • v0.9.4(May 17, 2022)


    • Remove HTML tags in malformed content types (#229)
    • Maximal number of errors recorded in Part limited (#240)
    • Builder: Support other parts (#244)
    • Additional decoding in mail address (#247)
    • Integration test include Go 1.18


    • Fix for quote-printed utf-8 header with quotes (#237)
    • Parse address joined with semicolons (#238)
    • Use extended parser after fixing address list (#239)
    • Parse media types which are escaped at first rune (#246)


    • Rely on stdlib for decoding to UTF-8, simplifies address parsing (#234)
    Source code(tar.gz)
    Source code(zip)
  • v0.9.3(Jan 29, 2022)


    • Support for more charsets (#230)
    • fixMangledMediaType now removes extra content-type parts (#225)


    • Fix new lines (ie in filenames) in mediatype.Parse (#224)
    • Fix crash in QPCleaner, when line is too long and buffer is almost full (#220)
    Source code(tar.gz)
    Source code(zip)
  • v0.9.2(Aug 21, 2021)


    • Auto-quote header parameters containing whitespace (#209)


    • Remove leading header parameter whitespace (#208)


    • Move ParseMediaType to its own mediatype package to reduce the length of header.go. Introduce wrapper func to preserve public API.
    Source code(tar.gz)
    Source code(zip)
  • v0.9.1(Jul 31, 2021)


    • mime-dump now prints a stack trace when parsing fails for easier debugging


    • Handle trailing whitespace in ; separated headers (#195, thanks demofrager)
    • Ignore empty sections in ; separated headers (#199, thanks pavelbazika)
    • Handle very long lines inside mime boundaries (#200, thanks pavelbazika)
    • Handle 8-bit characters in unencoded media type params (#201, thanks pavelbazika)
    • Handle tiny destination buffers and long lines in quoted-printable blocks (#203)


    • Encoder now uses QP or b64 encoding for 8-bit filenames instead of flattening to ASCII (#197, thanks Alexfilus)
    Source code(tar.gz)
    Source code(zip)
  • v0.9.0(May 1, 2021)


    • SendWithReversePath method to builder, allows specifying a reverse-path that differs from the from address (#179, thanks cgroschupp)
    • A Sender interface that allows our users to provide their own mail sending routines, or mock them in tests. #182


    • Reject empty addresses during builder validation (#187, thanks jawr)
    • Allow unset subject line during builder validation (#191, thanks psanford)


    • Updated dependencies
    Source code(tar.gz)
    Source code(zip)
  • v0.8.4(Dec 18, 2020)

  • v0.8.3(Nov 6, 2020)


    • Reverted folded header parsing changes due to compatibility problems (#172)
    • Improved performance and memory consumption of boundary reader (#170, thanks bttrfl and dcormier)
    Source code(tar.gz)
    Source code(zip)
  • v0.8.2(Oct 10, 2020)


    • Use DFS instead of BFS to locate HTML body to match behavior of popular email clients (#157, thanks huaconghub)
    • Improvements to media type parsing
    • Improvements to unescaping quotes with higher codepoints (#165, thanks pavelbazika)
    • Improvements to folded header parsing (#166, thanks pacellig)
    Source code(tar.gz)
    Source code(zip)
  • v0.8.1(May 26, 2020)


    • Handle incorrectly indented headers (#149, thanks requaos)
    • Handle trailing separator characters in header (#154, thanks joekamibeppu)


    • enmime no longer uses git-flow, and will now accept PRs against master
    Source code(tar.gz)
    Source code(zip)
  • v0.8.0(Feb 23, 2020)


    • Inject a application/octet-stream as default content type when none is present (#140, thanks requaos)
    • Add support for content-type params to part & encoding (#148, thanks pzeinlinger)
    • UTF-7 support (#17)


    • Handle missing parameter values in the middle of the media parameter list (#139, thanks requaos)
    • Fix boundaryReader to respect length instead of capacity (#145, thanks dcormier)
    • Handle very empty mime parts (#144, thanks dcormier)
    Source code(tar.gz)
    Source code(zip)
  • v0.7.0(Nov 24, 2019)


    • Public DecodeHeaders function for getting header data without processing the body parts (thanks requaos.)
    • Test coverage over 90% (thanks requaos!)


    • Update dependencies


    • Do not attempt to detect character set for short messages (#131, thanks requaos.)
    • Possible slice out of bounds error (#134, thanks requaos.)
    • Tests on Go 1.13 no longer fail due to textproto change (#137, thanks to requaos.)
    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Aug 11, 2019)


    • Make ParseMediaType public.


    • Improve quoted display name handling (#112, thanks to requaos.)
    • Refactor MIME part boundary detection (thanks to requaos.)
    • Several improvements to MIME attribute decoding (thanks to requaos.)
    • Detect text/plain attachments properly (thanks to davrux.)
    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Dec 16, 2018)


    • Use github.com/pkg/errors to decorate errors with stack traces (thanks to dcomier.)
    • Several improvements to Content-Type header decoding (thanks to dcormier.)
    • File modification date to encode/decode (thanks to dann7387.)
    • Handle non-delimited address lists (thanks to requaos.)
    • RFC-2047 attribute name deocding (thanks to requaos.)


    • Only detect charset on text/* parts (thanks to dcormier.)
    • Stop adding extra newline during encode (thanks to dann7387.)
    • Math bug in selecting QP or base64 encoding (thanks to dann7387.)
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Nov 22, 2018)


    • Override declared character set if another is detected with high confidence (thanks to nerdlich.)
    • Handle unquoted specials in media type parameters (thanks to requaos.)
    • Handle barren Content-Type headers (thanks to dcormier.)
    • Better handle malformed media type parameters (thanks to dcormier.)


    • Use iso-8859-1 character map when implicitly declared (thanks to requaos.)
    • Treat "inline" disposition as message content, not attachment unless it is accompanied by parameters (e.g. a filename, thanks to requaos.)
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Nov 1, 2018)


    • CLI utils now output inlines and other parts in addition to attachments.
    • Clone() method to Envelope and Part (thanks to nerdlich.)
    • GetHeaderKeys() method to Envelope (thanks to allenluce.)
    • GetHeaderValues() plus a suite of setters for Envelope (thanks to nerdlich.)


    • Use value instead of pointer receivers and return types on MailBuilder methods. Cleaner API, but may break some users.
    • enmime.Error now conforms to the Go error interface, its String() method is now deprecated.
    • NewPart() constructor no longer takes a parent parameter.
    • Part.Errors now holds pointers, matching Envelope.Errors.


    • Content is now populated for binary-only mails root part (thank to ostcar.)


    • Part no longer implements io.Reader, content is stored as a byte slice in Part.Content instead.
    Source code(tar.gz)
    Source code(zip)
James Hillyerd
Google SWE, Go and Rust enthusiast. He/him.
James Hillyerd
Go Mail - A cross platform mail driver for GoLang.

Go Mail aims to unify multiple popular mail API's (SparkPost, MailGun & SendGrid) into a singular easy to use interface. Email sending is seriously simple and great for allowing the developer to choose what platform they use.

Ainsley Clark 169 Dec 16, 2022
Mail-alias-resolve-ldap - Resolve mail alias addresses in LDAP

alias-resolve-ldap alias-resolve-ldap was written to be used as a hook for the c

Björn Busse 1 Jan 30, 2022
An email MIME artist for golang

Marcel is a tool to generate IETF compliant emails in raw MIME format. I mainly use this for generating emails with attachments and sending them via amazon SES. If that's what you're doing too, you may want notifications

David Banham 24 Nov 7, 2022
Golang package that generates clean, responsive HTML e-mails for sending transactional mail

Hermes Hermes is the Go port of the great mailgen engine for Node.js. Check their work, it's awesome! It's a package that generates clean, responsive

Mathieu Cornic 2.6k Dec 28, 2022
:envelope: A streaming Go library for the Internet Message Format and mail messages

go-message A Go library for the Internet Message Format. It implements: RFC 5322: Internet Message Format RFC 2045, RFC 2046 and RFC 2047: Multipurpos

Simon Ser 288 Dec 26, 2022
Filtering spam in mail server, protecting both client privacy and server algorithm

HE Spamfilter SNUCSE 2021 "Intelligent Computing System Design Project" Hyesun Kwak Myeonghwan Ahn Dongwon Lee abstract Naïve Bayesian spam filtering

Myeonghwan Ahn 1 Mar 23, 2022
Inline styling for html mail in golang

go-premailer Inline styling for HTML mail in golang Document install go get github.com/vanng822/go-premailer/premailer Example import ( "fmt" "gith

Nguyen Van Nhu 96 Nov 30, 2022
Go library for sending mail with the Mailgun API.

Mailgun with Go Go library for interacting with the Mailgun API. Usage package main import ( "context" "fmt" "log" "time" "githu

Mailgun Team 626 Dec 25, 2022
✉️ Composable all-in-one mail server.

Maddy Mail Server Composable all-in-one mail server. Maddy Mail Server implements all functionality required to run a e-mail server. It can send messa

Max Mazurov 3.7k Dec 27, 2022
an MDA that sends a webhook on recieval of mail

an MDA that sends a webhook on recieval of mail

forlater 10 Aug 13, 2022
📧 Example of sending mail via SendGrid in Golang.

?? go-sendgrid-example Example of sending mail via SendGrid in Golang. Get it started $ make setup # Edit environment variables $ vim ./env/local.env

ducci 1 Jan 11, 2022
Mail_sender - This library is for sending emails from your mail

Mail Sender This library is for sending emails from your mail Installation mail_

null 1 Dec 30, 2021
Mcopa - A library allows for parsing an email message into a more convenient form than the net/mail provides

Mail content parsing This library allows for parsing an email message into a mor

Mr Chen 0 Jan 1, 2022
Simple tool to test SMTP mail send with various settings including TLS1.1 downgrade

smtptest Simple tool to test SMTP mail send with various settings including TLS1.1 downgrade All settings are configurable in the config.yaml file ser

Mario 1 Sep 19, 2022
Go-mail - Email service using Kafka consumer

?? The Project This project consists in a Kafka consumer that reads messages of

Gustavo Belmonte Cioccari 2 Feb 5, 2022
Golang package for send email. Support keep alive connection, TLS and SSL. Easy for bulk SMTP.

Go Simple Mail The best way to send emails in Go with SMTP Keep Alive and Timeout for Connect and Send. IMPORTANT Examples in this README are for v2.2

Santiago De la Cruz 415 Jan 8, 2023
Hxgomail - Gomail - a simple and efficient package to send emails

Gomail Introduction Gomail is a simple and efficient package to send emails. It

null 0 Jan 4, 2022
DKIM package for golang

go-dkim DKIM package for Golang Getting started Install go get github.com/toorop/go-dkim Warning: you need to use Go 1.4.2-master or 1.4.3 (when it

Stéphane Depierrepont 85 Dec 10, 2022
POP-3 client package for Go.

GOP-3 (Go + POP-3) is a POP-3 client for Go. It has experimental purpose and it is still under development. RFC 1939 document has been followed while developing package.

Gökhan Özeloğlu 10 Dec 25, 2021