diff --git a/msg.go b/msg.go index aa33c13..608e080 100644 --- a/msg.go +++ b/msg.go @@ -190,7 +190,16 @@ func (m *Msg) Charset() string { } // SetHeader sets a generic header field of the Msg +// For adding address headers like "To:" or "From", see SetAddrHeader +// +// Deprecated: This method only exists for compatibility reason. Please use SetGenHeader instead func (m *Msg) SetHeader(h Header, v ...string) { + m.SetGenHeader(h, v...) +} + +// SetGenHeader sets a generic header field of the Msg +// For adding address headers like "To:" or "From", see SetAddrHeader +func (m *Msg) SetGenHeader(h Header, v ...string) { if m.genHeader == nil { m.genHeader = make(map[Header][]string) } @@ -203,6 +212,15 @@ func (m *Msg) SetHeader(h Header, v ...string) { // SetHeaderPreformatted sets a generic header field of the Msg which content is // already preformated. // +// Deprecated: This method only exists for compatibility reason. Please use +// SetGenHeaderPreformatted instead +func (m *Msg) SetHeaderPreformatted(h Header, v string) { + m.SetGenHeaderPreformatted(h, v) +} + +// SetGenHeaderPreformatted sets a generic header field of the Msg which content is +// already preformated. +// // This method does not take a slice of values but only a single value. This is // due to the fact, that we do not perform any content alteration and expect the // user has already done so @@ -210,8 +228,8 @@ func (m *Msg) SetHeader(h Header, v ...string) { // **Please note:** This method should be used only as a last resort. Since the // user is respondible for the formating of the message header, go-mail cannot // guarantee the fully compliance with the RFC 2822. It is recommended to use -// SetHeader instead. -func (m *Msg) SetHeaderPreformatted(h Header, v string) { +// SetGenHeader instead. +func (m *Msg) SetGenHeaderPreformatted(h Header, v string) { if m.preformHeader == nil { m.preformHeader = make(map[Header]string) } @@ -349,7 +367,7 @@ func (m *Msg) ReplyTo(r string) error { if err != nil { return fmt.Errorf("failed to parse reply-to address: %w", err) } - m.SetHeader(HeaderReplyTo, rt.String()) + m.SetGenHeader(HeaderReplyTo, rt.String()) return nil } @@ -371,7 +389,7 @@ func (m *Msg) addAddr(h AddrHeader, a string) error { // Subject sets the "Subject" header field of the Msg func (m *Msg) Subject(s string) { - m.SetHeader(HeaderSubject, s) + m.SetGenHeader(HeaderSubject, s) } // SetMessageID generates a random message id for the mail @@ -390,25 +408,25 @@ func (m *Msg) SetMessageID() { // SetMessageIDWithValue sets the message id for the mail func (m *Msg) SetMessageIDWithValue(v string) { - m.SetHeader(HeaderMessageID, fmt.Sprintf("<%s>", v)) + m.SetGenHeader(HeaderMessageID, fmt.Sprintf("<%s>", v)) } // SetBulk sets the "Precedence: bulk" genHeader which is recommended for // automated mails like OOO replies // See: https://www.rfc-editor.org/rfc/rfc2076#section-3.9 func (m *Msg) SetBulk() { - m.SetHeader(HeaderPrecedence, "bulk") + m.SetGenHeader(HeaderPrecedence, "bulk") } // SetDate sets the Date genHeader field to the current time in a valid format func (m *Msg) SetDate() { ts := time.Now().Format(time.RFC1123Z) - m.SetHeader(HeaderDate, ts) + m.SetGenHeader(HeaderDate, ts) } // SetDateWithValue sets the Date genHeader field to the provided time in a valid format func (m *Msg) SetDateWithValue(t time.Time) { - m.SetHeader(HeaderDate, t.Format(time.RFC1123Z)) + m.SetGenHeader(HeaderDate, t.Format(time.RFC1123Z)) } // SetImportance sets the Msg Importance/Priority header to given Importance @@ -416,21 +434,21 @@ func (m *Msg) SetImportance(i Importance) { if i == ImportanceNormal { return } - m.SetHeader(HeaderImportance, i.String()) - m.SetHeader(HeaderPriority, i.NumString()) - m.SetHeader(HeaderXPriority, i.XPrioString()) - m.SetHeader(HeaderXMSMailPriority, i.NumString()) + m.SetGenHeader(HeaderImportance, i.String()) + m.SetGenHeader(HeaderPriority, i.NumString()) + m.SetGenHeader(HeaderXPriority, i.XPrioString()) + m.SetGenHeader(HeaderXMSMailPriority, i.NumString()) } // SetOrganization sets the provided string as Organization header for the Msg func (m *Msg) SetOrganization(o string) { - m.SetHeader(HeaderOrganization, o) + m.SetGenHeader(HeaderOrganization, o) } // SetUserAgent sets the User-Agent/X-Mailer header for the Msg func (m *Msg) SetUserAgent(a string) { - m.SetHeader(HeaderUserAgent, a) - m.SetHeader(HeaderXMailer, a) + m.SetGenHeader(HeaderUserAgent, a) + m.SetGenHeader(HeaderXMailer, a) } // RequestMDNTo adds the Disposition-Notification-To header to request a MDN from the receiving end @@ -511,6 +529,60 @@ func (m *Msg) GetRecipients() ([]string, error) { return rl, nil } +// GetAddrHeader returns the content of the requested address header of the Msg +func (m *Msg) GetAddrHeader(h AddrHeader) []*mail.Address { + return m.addrHeader[h] +} + +// GetAddrHeaderString returns the address string of the requested address header of the Msg +func (m *Msg) GetAddrHeaderString(h AddrHeader) []string { + var al []string + for i := range m.addrHeader[h] { + al = append(al, m.addrHeader[h][i].String()) + } + return al +} + +// GetFrom returns the content of the From address header of the Msg +func (m *Msg) GetFrom() []*mail.Address { + return m.GetAddrHeader(HeaderFrom) +} + +// GetFromString returns the content of the From address header of the Msg as string slice +func (m *Msg) GetFromString() []string { + return m.GetAddrHeaderString(HeaderFrom) +} + +// GetTo returns the content of the To address header of the Msg +func (m *Msg) GetTo() []*mail.Address { + return m.GetAddrHeader(HeaderTo) +} + +// GetToString returns the content of the To address header of the Msg as string slice +func (m *Msg) GetToString() []string { + return m.GetAddrHeaderString(HeaderTo) +} + +// GetCc returns the content of the Cc address header of the Msg +func (m *Msg) GetCc() []*mail.Address { + return m.GetAddrHeader(HeaderCc) +} + +// GetCcString returns the content of the Cc address header of the Msg as string slice +func (m *Msg) GetCcString() []string { + return m.GetAddrHeaderString(HeaderCc) +} + +// GetBcc returns the content of the Bcc address header of the Msg +func (m *Msg) GetBcc() []*mail.Address { + return m.GetAddrHeader(HeaderBcc) +} + +// GetBccString returns the content of the Bcc address header of the Msg as string slice +func (m *Msg) GetBccString() []string { + return m.GetAddrHeaderString(HeaderBcc) +} + // GetGenHeader returns the content of the requested generic header of the Msg func (m *Msg) GetGenHeader(h Header) []string { return m.genHeader[h] @@ -948,7 +1020,7 @@ func (m *Msg) addDefaultHeader() { if _, ok := m.genHeader[HeaderMessageID]; !ok { m.SetMessageID() } - m.SetHeader(HeaderMIMEVersion, string(m.mimever)) + m.SetGenHeader(HeaderMIMEVersion, string(m.mimever)) } // fileFromEmbedFS returns a File pointer from a given file in the provided embed.FS diff --git a/msg_test.go b/msg_test.go index 8cb3b6d..004be40 100644 --- a/msg_test.go +++ b/msg_test.go @@ -255,8 +255,8 @@ func TestApplyMiddlewares(t *testing.T) { } } -// TestMsg_SetHeader tests Msg.SetHeader -func TestMsg_SetHeader(t *testing.T) { +// TestMsg_SetGenHeader tests Msg.SetGenHeader +func TestMsg_SetGenHeader(t *testing.T) { tests := []struct { name string header Header @@ -269,9 +269,9 @@ func TestMsg_SetHeader(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { m := NewMsg() - m.SetHeader(tt.header, tt.values...) + m.SetGenHeader(tt.header, tt.values...) if m.genHeader[tt.header] == nil { - t.Errorf("SetHeader() failed. Tried to set header %s, but it is empty", tt.header) + t.Errorf("SetGenHeader() failed. Tried to set header %s, but it is empty", tt.header) return } for _, v := range tt.values { @@ -282,15 +282,15 @@ func TestMsg_SetHeader(t *testing.T) { } } if !found { - t.Errorf("SetHeader() failed. Value %s not found in header field", v) + t.Errorf("SetGenHeader() failed. Value %s not found in header field", v) } } }) } } -// TestMsg_SetHeaderPreformatted tests Msg.SetHeaderPreformatted -func TestMsg_SetHeaderPreformatted(t *testing.T) { +// TestMsg_SetGenHeaderPreformatted tests Msg.SetGenHeaderPreformatted +func TestMsg_SetGenHeaderPreformatted(t *testing.T) { tests := []struct { name string header Header @@ -305,14 +305,14 @@ func TestMsg_SetHeaderPreformatted(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { m := &Msg{} - m.SetHeaderPreformatted(tt.header, tt.value) + m.SetGenHeaderPreformatted(tt.header, tt.value) m = NewMsg() - m.SetHeaderPreformatted(tt.header, tt.value) + m.SetGenHeaderPreformatted(tt.header, tt.value) if m.preformHeader[tt.header] == "" { - t.Errorf("SetHeaderPreformatted() failed. Tried to set header %s, but it is empty", tt.header) + t.Errorf("SetGenHeaderPreformatted() failed. Tried to set header %s, but it is empty", tt.header) } if m.preformHeader[tt.header] != tt.value { - t.Errorf("SetHeaderPreformatted() failed. Expected: %q, got: %q", tt.value, + t.Errorf("SetGenHeaderPreformatted() failed. Expected: %q, got: %q", tt.value, m.preformHeader[tt.header]) } buf := bytes.Buffer{} @@ -322,7 +322,7 @@ func TestMsg_SetHeaderPreformatted(t *testing.T) { return } if !strings.Contains(buf.String(), fmt.Sprintf("%s: %s%s", tt.header, tt.value, SingleNewLine)) { - t.Errorf("SetHeaderPreformatted() failed. Unable to find correctly formated header in " + + t.Errorf("SetGenHeaderPreformatted() failed. Unable to find correctly formated header in " + "mail message output") } }) @@ -1703,9 +1703,9 @@ func TestMsg_Write(t *testing.T) { func TestMsg_WriteWithLongHeader(t *testing.T) { m := NewMsg() m.SetBodyString(TypeTextPlain, "Plain") - m.SetHeader(HeaderContentLang, "de", "en", "fr", "es", "xxxx", "yyyy", "de", "en", "fr", + m.SetGenHeader(HeaderContentLang, "de", "en", "fr", "es", "xxxx", "yyyy", "de", "en", "fr", "es", "xxxx", "yyyy", "de", "en", "fr", "es", "xxxx", "yyyy", "de", "en", "fr") - m.SetHeader(HeaderContentID, "XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX", + m.SetGenHeader(HeaderContentID, "XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXX") wbuf := bytes.Buffer{} n, err := m.WriteTo(&wbuf) @@ -2324,3 +2324,228 @@ func TestMsg_GetGenHeader(t *testing.T) { t.Errorf("GetGenHeader on subject failed. Expected: %q, got: %q", "this is a test", sa[0]) } } + +// TestMsg_GetAddrHeader will test the Msg.GetAddrHeader method +func TestMsg_GetAddrHeader(t *testing.T) { + m := NewMsg() + if err := m.FromFormat("Toni Sender", "sender@example.com"); err != nil { + t.Errorf("failed to set FROM address: %s", err) + } + if err := m.AddToFormat("Toni To", "to@example.com"); err != nil { + t.Errorf("failed to set TO address: %s", err) + } + if err := m.AddCcFormat("Toni Cc", "cc@example.com"); err != nil { + t.Errorf("failed to set CC address: %s", err) + } + if err := m.AddBccFormat("Toni Bcc", "bcc@example.com"); err != nil { + t.Errorf("failed to set BCC address: %s", err) + } + fh := m.GetAddrHeader(HeaderFrom) + if len(fh) <= 0 { + t.Errorf("GetAddrHeader on FROM failed. Got empty slice") + return + } + if fh[0].String() == "" { + t.Errorf("GetAddrHeader on FROM failed. Got empty value") + } + if fh[0].String() != `"Toni Sender" ` { + t.Errorf("GetAddrHeader on FROM failed. Expected: %q, got: %q", + `"Toni Sender" "`, fh[0].String()) + } + th := m.GetAddrHeader(HeaderTo) + if len(th) <= 0 { + t.Errorf("GetAddrHeader on TO failed. Got empty slice") + return + } + if th[0].String() == "" { + t.Errorf("GetAddrHeader on TO failed. Got empty value") + } + if th[0].String() != `"Toni To" ` { + t.Errorf("GetAddrHeader on TO failed. Expected: %q, got: %q", + `"Toni To" "`, th[0].String()) + } + ch := m.GetAddrHeader(HeaderCc) + if len(ch) <= 0 { + t.Errorf("GetAddrHeader on CC failed. Got empty slice") + return + } + if ch[0].String() == "" { + t.Errorf("GetAddrHeader on CC failed. Got empty value") + } + if ch[0].String() != `"Toni Cc" ` { + t.Errorf("GetAddrHeader on CC failed. Expected: %q, got: %q", + `"Toni Cc" "`, ch[0].String()) + } + bh := m.GetAddrHeader(HeaderBcc) + if len(bh) <= 0 { + t.Errorf("GetAddrHeader on BCC failed. Got empty slice") + return + } + if bh[0].String() == "" { + t.Errorf("GetAddrHeader on BCC failed. Got empty value") + } + if bh[0].String() != `"Toni Bcc" ` { + t.Errorf("GetAddrHeader on BCC failed. Expected: %q, got: %q", + `"Toni Bcc" "`, bh[0].String()) + } +} + +// TestMsg_GetFrom will test the Msg.GetFrom method +func TestMsg_GetFrom(t *testing.T) { + m := NewMsg() + if err := m.FromFormat("Toni Sender", "sender@example.com"); err != nil { + t.Errorf("failed to set FROM address: %s", err) + } + fh := m.GetFrom() + if len(fh) <= 0 { + t.Errorf("GetFrom failed. Got empty slice") + return + } + if fh[0].String() == "" { + t.Errorf("GetFrom failed. Got empty value") + } + if fh[0].String() != `"Toni Sender" ` { + t.Errorf("GetFrom failed. Expected: %q, got: %q", + `"Toni Sender" "`, fh[0].String()) + } +} + +// TestMsg_GetFromString will test the Msg.GetFromString method +func TestMsg_GetFromString(t *testing.T) { + m := NewMsg() + if err := m.FromFormat("Toni Sender", "sender@example.com"); err != nil { + t.Errorf("failed to set FROM address: %s", err) + } + fh := m.GetFromString() + if len(fh) <= 0 { + t.Errorf("GetFromString failed. Got empty slice") + return + } + if fh[0] == "" { + t.Errorf("GetFromString failed. Got empty value") + } + if fh[0] != `"Toni Sender" ` { + t.Errorf("GetFromString failed. Expected: %q, got: %q", + `"Toni Sender" "`, fh[0]) + } +} + +// TestMsg_GetTo will test the Msg.GetTo method +func TestMsg_GetTo(t *testing.T) { + m := NewMsg() + if err := m.AddToFormat("Toni To", "to@example.com"); err != nil { + t.Errorf("failed to set TO address: %s", err) + } + fh := m.GetTo() + if len(fh) <= 0 { + t.Errorf("GetTo failed. Got empty slice") + return + } + if fh[0].String() == "" { + t.Errorf("GetTo failed. Got empty value") + } + if fh[0].String() != `"Toni To" ` { + t.Errorf("GetTo failed. Expected: %q, got: %q", + `"Toni To" "`, fh[0].String()) + } +} + +// TestMsg_GetToString will test the Msg.GetToString method +func TestMsg_GetToString(t *testing.T) { + m := NewMsg() + if err := m.AddToFormat("Toni To", "to@example.com"); err != nil { + t.Errorf("failed to set TO address: %s", err) + } + fh := m.GetToString() + if len(fh) <= 0 { + t.Errorf("GetToString failed. Got empty slice") + return + } + if fh[0] == "" { + t.Errorf("GetToString failed. Got empty value") + } + if fh[0] != `"Toni To" ` { + t.Errorf("GetToString failed. Expected: %q, got: %q", + `"Toni To" "`, fh[0]) + } +} + +// TestMsg_GetCc will test the Msg.GetCc method +func TestMsg_GetCc(t *testing.T) { + m := NewMsg() + if err := m.AddCcFormat("Toni Cc", "cc@example.com"); err != nil { + t.Errorf("failed to set TO address: %s", err) + } + fh := m.GetCc() + if len(fh) <= 0 { + t.Errorf("GetCc failed. Got empty slice") + return + } + if fh[0].String() == "" { + t.Errorf("GetCc failed. Got empty value") + } + if fh[0].String() != `"Toni Cc" ` { + t.Errorf("GetCc failed. Expected: %q, got: %q", + `"Toni Cc" "`, fh[0].String()) + } +} + +// TestMsg_GetCcString will test the Msg.GetCcString method +func TestMsg_GetCcString(t *testing.T) { + m := NewMsg() + if err := m.AddCcFormat("Toni Cc", "cc@example.com"); err != nil { + t.Errorf("failed to set TO address: %s", err) + } + fh := m.GetCcString() + if len(fh) <= 0 { + t.Errorf("GetCcString failed. Got empty slice") + return + } + if fh[0] == "" { + t.Errorf("GetCcString failed. Got empty value") + } + if fh[0] != `"Toni Cc" ` { + t.Errorf("GetCcString failed. Expected: %q, got: %q", + `"Toni Cc" "`, fh[0]) + } +} + +// TestMsg_GetBcc will test the Msg.GetBcc method +func TestMsg_GetBcc(t *testing.T) { + m := NewMsg() + if err := m.AddBccFormat("Toni Bcc", "bcc@example.com"); err != nil { + t.Errorf("failed to set TO address: %s", err) + } + fh := m.GetBcc() + if len(fh) <= 0 { + t.Errorf("GetBcc failed. Got empty slice") + return + } + if fh[0].String() == "" { + t.Errorf("GetBcc failed. Got empty value") + } + if fh[0].String() != `"Toni Bcc" ` { + t.Errorf("GetBcc failed. Expected: %q, got: %q", + `"Toni Cc" "`, fh[0].String()) + } +} + +// TestMsg_GetBccString will test the Msg.GetBccString method +func TestMsg_GetBccString(t *testing.T) { + m := NewMsg() + if err := m.AddBccFormat("Toni Bcc", "bcc@example.com"); err != nil { + t.Errorf("failed to set TO address: %s", err) + } + fh := m.GetBccString() + if len(fh) <= 0 { + t.Errorf("GetBccString failed. Got empty slice") + return + } + if fh[0] == "" { + t.Errorf("GetBccString failed. Got empty value") + } + if fh[0] != `"Toni Bcc" ` { + t.Errorf("GetBccString failed. Expected: %q, got: %q", + `"Toni Cc" "`, fh[0]) + } +}