From 7ecd6092e1ec52a548c68161dd9f04d0af39e63f Mon Sep 17 00:00:00 2001 From: Shulhan Date: Mon, 21 Feb 2022 01:38:07 +0700 Subject: lib/email: set the header Date field on NewMultipart The Date field value is set to current time on the system that generated the message. The date format is set to "Mon, 2 Jan 2006 15:04:05 -0700" according to RFC 5322 section 3.3. --- lib/email/email.go | 13 +++++++++++++ lib/email/message.go | 12 ++++++++++++ lib/smtp/mail_tx_example_test.go | 20 ++++++++++++++++++-- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/email/email.go b/lib/email/email.go index 4471a39e..0e56fb4d 100644 --- a/lib/email/email.go +++ b/lib/email/email.go @@ -4,10 +4,13 @@ package email +import "time" + const ( contentTypeMultipartAlternative = "multipart/alternative" contentTypeTextPlain = `text/plain; charset="utf-8"` contentTypeTextHTML = `text/html; charset="utf-8"` + DateFormat = "Mon, 2 Jan 2006 15:04:05 -0700" encodingQuotedPrintable = "quoted-printable" mimeVersion1 = "1.0" ) @@ -17,4 +20,14 @@ const ( lf byte = '\n' ) +// +// Epoch return the UNIX timestamp in seconds. +// +// This variable is exported to allow function that use date and/or time can +// be tested with fixed, predictable value. +// +var Epoch = func() int64 { + return time.Now().Unix() +} + var boundSeps = []byte{'-', '-'} diff --git a/lib/email/message.go b/lib/email/message.go index 4bc4de12..eafdc144 100644 --- a/lib/email/message.go +++ b/lib/email/message.go @@ -10,6 +10,7 @@ import ( "fmt" "io/ioutil" "strings" + "time" libbytes "github.com/shuLhan/share/lib/bytes" "github.com/shuLhan/share/lib/email/dkim" @@ -31,11 +32,22 @@ type Message struct { func NewMultipart(from, to, subject, bodyText, bodyHTML []byte) ( msg *Message, err error, ) { + var ( + logp = "NewMultipart" + timeNow = time.Unix(Epoch(), 0) + dateValue = timeNow.Format(DateFormat) + ) + msg = &Message{ Header: &Header{}, Body: &Body{}, } + err = msg.Header.Set(FieldTypeDate, []byte(dateValue)) + if err != nil { + return nil, fmt.Errorf("%s: %w", logp, err) + } + err = msg.Header.Set(FieldTypeFrom, from) if err != nil { return nil, fmt.Errorf("email.NewMultipart: %w", err) diff --git a/lib/smtp/mail_tx_example_test.go b/lib/smtp/mail_tx_example_test.go index 28e3653f..0b4dda52 100644 --- a/lib/smtp/mail_tx_example_test.go +++ b/lib/smtp/mail_tx_example_test.go @@ -9,6 +9,8 @@ import ( "fmt" "log" "math/rand" + "regexp" + "time" "github.com/shuLhan/share/lib/email" ) @@ -18,13 +20,20 @@ func ExampleNewMailTx() { // // [1] github.com/shuLhan/share/lib/email + // Overwrite the email.Epoch to make the example works. + email.Epoch = func() int64 { + return 1645600000 + } + var ( txFrom = "Postmaster " fromAddress = []byte("Noreply ") + toAddresses = []byte("John , Jane ") subject = []byte(`Example subject`) bodyText = []byte(`Email body as plain text`) bodyHtml = []byte(`Email body as HTML`) - toAddresses = []byte("John , Jane ") + timeNowUtc = time.Unix(email.Epoch(), 0).UTC() + dateNowUtc = timeNowUtc.Format(email.DateFormat) recipients []string mboxes []*email.Mailbox @@ -65,14 +74,21 @@ func ExampleNewMailTx() { fmt.Printf("Tx Recipients: %s\n", mailtx.Recipients) // In order to make the example Output works, we need to replace all - // CRLF with LF. + // CRLF with LF and "date:" with the system timezone. data = bytes.ReplaceAll(mailtx.Data, []byte("\r\n"), []byte("\n")) + //fmt.Printf("timeNowUtc: %s\n", timeNowUtc) + //fmt.Printf("dateNowUtc: %s\n", dateNowUtc) + + reDate := regexp.MustCompile(`^date: Wed(.*) \+....`) + data = reDate.ReplaceAll(data, []byte(`date: `+dateNowUtc)) + fmt.Printf("Tx Data:\n%s", data) //Output: //Tx From: Postmaster //Tx Recipients: [john@example.com jane@example.com] //Tx Data: + //date: Wed, 23 Feb 2022 07:06:40 +0000 //from: Noreply //to: John , Jane //subject: Example subject -- cgit v1.3