Merge pull request #83 from wneessen/feature/80_add-getaddrheader

#80: GetAddrHeader and SetGenHeader
This commit is contained in:
Winni Neessen 2022-11-19 11:31:28 +01:00 committed by GitHub
commit 2a228c5b08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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
// 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

View file

@ -256,8 +256,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
@ -270,9 +270,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 {
@ -283,15 +283,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
@ -306,14 +306,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{}
@ -323,7 +323,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")
}
})
@ -1728,9 +1728,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)
@ -2349,3 +2349,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" <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])
}
}