#80: GetAddrHeader and SetGenHeader

This PR introduces two major changes:

* SetHeader and SetHeaderPreformatted have been deprecated in favour of SetGenHeader and SetGenHeaderPreformatted
  As pointed out in #80 the naming was pretty confusing, given that we already have SetAddrHeader. With the new naming convention it should be more clear. For compatibility reasons the old methods have been kept for now but in reality they are just aliases to the new methods
* GetAddrHeader and GetAddrHeaderString have been introduced
  As requested in #80 analogous to GetGenHeader we also need a similar method for the address headers. Since address headers are *mail.Address pointer, we've also added a *String method that will extract the address string and return a string slice instead
  Additionally we're introducing methods for the actual address headers: GetTo, GetFrom, GetCc and GetBcc (with a *String counterpart as well). This way the user has full flexibility. Either they use the more "low-level" GetAddrHeader method or the higher level methods for the corresponding address type
This commit is contained in:
Winni Neessen 2022-11-19 11:22:20 +01:00
parent 957e705f16
commit 17b9d2ccf6
Signed by: wneessen
GPG key ID: 385AC9889632126E
2 changed files with 327 additions and 30 deletions

104
msg.go
View file

@ -190,7 +190,16 @@ func (m *Msg) Charset() string {
} }
// SetHeader sets a generic header field of the Msg // 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) { 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 { if m.genHeader == nil {
m.genHeader = make(map[Header][]string) 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 // SetHeaderPreformatted sets a generic header field of the Msg which content is
// already preformated. // 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 // 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 // due to the fact, that we do not perform any content alteration and expect the
// user has already done so // 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 // **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 // 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 // guarantee the fully compliance with the RFC 2822. It is recommended to use
// SetHeader instead. // SetGenHeader instead.
func (m *Msg) SetHeaderPreformatted(h Header, v string) { func (m *Msg) SetGenHeaderPreformatted(h Header, v string) {
if m.preformHeader == nil { if m.preformHeader == nil {
m.preformHeader = make(map[Header]string) m.preformHeader = make(map[Header]string)
} }
@ -349,7 +367,7 @@ func (m *Msg) ReplyTo(r string) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to parse reply-to address: %w", err) return fmt.Errorf("failed to parse reply-to address: %w", err)
} }
m.SetHeader(HeaderReplyTo, rt.String()) m.SetGenHeader(HeaderReplyTo, rt.String())
return nil return nil
} }
@ -371,7 +389,7 @@ func (m *Msg) addAddr(h AddrHeader, a string) error {
// Subject sets the "Subject" header field of the Msg // Subject sets the "Subject" header field of the Msg
func (m *Msg) Subject(s string) { func (m *Msg) Subject(s string) {
m.SetHeader(HeaderSubject, s) m.SetGenHeader(HeaderSubject, s)
} }
// SetMessageID generates a random message id for the mail // 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 // SetMessageIDWithValue sets the message id for the mail
func (m *Msg) SetMessageIDWithValue(v string) { 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 // SetBulk sets the "Precedence: bulk" genHeader which is recommended for
// automated mails like OOO replies // automated mails like OOO replies
// See: https://www.rfc-editor.org/rfc/rfc2076#section-3.9 // See: https://www.rfc-editor.org/rfc/rfc2076#section-3.9
func (m *Msg) SetBulk() { 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 // SetDate sets the Date genHeader field to the current time in a valid format
func (m *Msg) SetDate() { func (m *Msg) SetDate() {
ts := time.Now().Format(time.RFC1123Z) 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 // SetDateWithValue sets the Date genHeader field to the provided time in a valid format
func (m *Msg) SetDateWithValue(t time.Time) { 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 // SetImportance sets the Msg Importance/Priority header to given Importance
@ -416,21 +434,21 @@ func (m *Msg) SetImportance(i Importance) {
if i == ImportanceNormal { if i == ImportanceNormal {
return return
} }
m.SetHeader(HeaderImportance, i.String()) m.SetGenHeader(HeaderImportance, i.String())
m.SetHeader(HeaderPriority, i.NumString()) m.SetGenHeader(HeaderPriority, i.NumString())
m.SetHeader(HeaderXPriority, i.XPrioString()) m.SetGenHeader(HeaderXPriority, i.XPrioString())
m.SetHeader(HeaderXMSMailPriority, i.NumString()) m.SetGenHeader(HeaderXMSMailPriority, i.NumString())
} }
// SetOrganization sets the provided string as Organization header for the Msg // SetOrganization sets the provided string as Organization header for the Msg
func (m *Msg) SetOrganization(o string) { 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 // SetUserAgent sets the User-Agent/X-Mailer header for the Msg
func (m *Msg) SetUserAgent(a string) { func (m *Msg) SetUserAgent(a string) {
m.SetHeader(HeaderUserAgent, a) m.SetGenHeader(HeaderUserAgent, a)
m.SetHeader(HeaderXMailer, a) m.SetGenHeader(HeaderXMailer, a)
} }
// RequestMDNTo adds the Disposition-Notification-To header to request a MDN from the receiving end // 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 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 // GetGenHeader returns the content of the requested generic header of the Msg
func (m *Msg) GetGenHeader(h Header) []string { func (m *Msg) GetGenHeader(h Header) []string {
return m.genHeader[h] return m.genHeader[h]
@ -948,7 +1020,7 @@ func (m *Msg) addDefaultHeader() {
if _, ok := m.genHeader[HeaderMessageID]; !ok { if _, ok := m.genHeader[HeaderMessageID]; !ok {
m.SetMessageID() 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 // fileFromEmbedFS returns a File pointer from a given file in the provided embed.FS

View file

@ -255,8 +255,8 @@ func TestApplyMiddlewares(t *testing.T) {
} }
} }
// TestMsg_SetHeader tests Msg.SetHeader // TestMsg_SetGenHeader tests Msg.SetGenHeader
func TestMsg_SetHeader(t *testing.T) { func TestMsg_SetGenHeader(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
header Header header Header
@ -269,9 +269,9 @@ func TestMsg_SetHeader(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
m := NewMsg() m := NewMsg()
m.SetHeader(tt.header, tt.values...) m.SetGenHeader(tt.header, tt.values...)
if m.genHeader[tt.header] == nil { 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 return
} }
for _, v := range tt.values { for _, v := range tt.values {
@ -282,15 +282,15 @@ func TestMsg_SetHeader(t *testing.T) {
} }
} }
if !found { 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 // TestMsg_SetGenHeaderPreformatted tests Msg.SetGenHeaderPreformatted
func TestMsg_SetHeaderPreformatted(t *testing.T) { func TestMsg_SetGenHeaderPreformatted(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
header Header header Header
@ -305,14 +305,14 @@ func TestMsg_SetHeaderPreformatted(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
m := &Msg{} m := &Msg{}
m.SetHeaderPreformatted(tt.header, tt.value) m.SetGenHeaderPreformatted(tt.header, tt.value)
m = NewMsg() m = NewMsg()
m.SetHeaderPreformatted(tt.header, tt.value) m.SetGenHeaderPreformatted(tt.header, tt.value)
if m.preformHeader[tt.header] == "" { 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 { 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]) m.preformHeader[tt.header])
} }
buf := bytes.Buffer{} buf := bytes.Buffer{}
@ -322,7 +322,7 @@ func TestMsg_SetHeaderPreformatted(t *testing.T) {
return return
} }
if !strings.Contains(buf.String(), fmt.Sprintf("%s: %s%s", tt.header, tt.value, SingleNewLine)) { 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") "mail message output")
} }
}) })
@ -1703,9 +1703,9 @@ func TestMsg_Write(t *testing.T) {
func TestMsg_WriteWithLongHeader(t *testing.T) { func TestMsg_WriteWithLongHeader(t *testing.T) {
m := NewMsg() m := NewMsg()
m.SetBodyString(TypeTextPlain, "Plain") 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") "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") "XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXX")
wbuf := bytes.Buffer{} wbuf := bytes.Buffer{}
n, err := m.WriteTo(&wbuf) 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]) 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" <sender@example.com>` {
t.Errorf("GetAddrHeader on FROM failed. Expected: %q, got: %q",
`"Toni Sender" <sender@example.com>"`, 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" <to@example.com>` {
t.Errorf("GetAddrHeader on TO failed. Expected: %q, got: %q",
`"Toni To" <to@example.com>"`, 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" <cc@example.com>` {
t.Errorf("GetAddrHeader on CC failed. Expected: %q, got: %q",
`"Toni Cc" <cc@example.com>"`, 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" <bcc@example.com>` {
t.Errorf("GetAddrHeader on BCC failed. Expected: %q, got: %q",
`"Toni Bcc" <bcc@example.com>"`, 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" <sender@example.com>` {
t.Errorf("GetFrom failed. Expected: %q, got: %q",
`"Toni Sender" <sender@example.com>"`, 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" <sender@example.com>` {
t.Errorf("GetFromString failed. Expected: %q, got: %q",
`"Toni Sender" <sender@example.com>"`, 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" <to@example.com>` {
t.Errorf("GetTo failed. Expected: %q, got: %q",
`"Toni To" <to@example.com>"`, 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" <to@example.com>` {
t.Errorf("GetToString failed. Expected: %q, got: %q",
`"Toni To" <to@example.com>"`, 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" <cc@example.com>` {
t.Errorf("GetCc failed. Expected: %q, got: %q",
`"Toni Cc" <cc@example.com>"`, 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" <cc@example.com>` {
t.Errorf("GetCcString failed. Expected: %q, got: %q",
`"Toni Cc" <cc@example.com>"`, 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" <bcc@example.com>` {
t.Errorf("GetBcc failed. Expected: %q, got: %q",
`"Toni Cc" <bcc@example.com>"`, 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" <bcc@example.com>` {
t.Errorf("GetBccString failed. Expected: %q, got: %q",
`"Toni Cc" <bcc@example.com>"`, fh[0])
}
}