Repository: inbucket/inbucket
Pull request #447 (2023-11-23 01:11:16)

event: Use pointers for InboundMessage addresses
To ease conversions to/from MessageMetadata

Signed-off-by: James Hillyerd <james@hillyerd.com>


coveralls: ## Pull Request Test Coverage Report for [Build 6964429926](https://coveralls.io/builds/64132726)


* **18** of **18**   **(100.0%)**  changed or added relevant lines in **2** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage decreased (**-0.06%**) to **55.097%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/64132726/badge)](https://coveralls.io/builds/64132726) |
| :-- | --: |
| Change from base [Build 6964342418](https://coveralls.io/builds/64132600): |  -0.06% |
| Covered Lines: | 2616 |
| Relevant Lines: | 4748 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/pkg/extension/event/events.go b/pkg/extension/event/events.go
index 554a8a7..c59f6bf 100644
--- a/pkg/extension/event/events.go
+++ b/pkg/extension/event/events.go
@@ -14,8 +14,8 @@ type AddressParts struct {
 // InboundMessage contains the basic header and mailbox data for a message being received.
 type InboundMessage struct {
 	Mailboxes []string
-	From      mail.Address
-	To        []mail.Address
+	From      *mail.Address
+	To        []*mail.Address
 	Subject   string
 	Size      int64
 }
diff --git a/pkg/extension/luahost/bind_inboundmessage.go b/pkg/extension/luahost/bind_inboundmessage.go
index 2b3d242..32bdca8 100644
--- a/pkg/extension/luahost/bind_inboundmessage.go
+++ b/pkg/extension/luahost/bind_inboundmessage.go
@@ -73,12 +73,12 @@ func inboundMessageIndex(ls *lua.LState) int {
 		}
 		ls.Push(lt)
 	case "from":
-		ls.Push(wrapMailAddress(ls, &m.From))
+		ls.Push(wrapMailAddress(ls, m.From))
 	case "to":
 		lt := &lua.LTable{}
 		for _, v := range m.To {
 			addr := v
-			lt.Append(wrapMailAddress(ls, &addr))
+			lt.Append(wrapMailAddress(ls, addr))
 		}
 		ls.Push(lt)
 	case "subject":
@@ -110,15 +110,15 @@ func inboundMessageNewIndex(ls *lua.LState) int {
 		})
 		m.Mailboxes = mailboxes
 	case "from":
-		m.From = *checkMailAddress(ls, 3)
+		m.From = checkMailAddress(ls, 3)
 	case "to":
 		lt := ls.CheckTable(3)
-		to := make([]mail.Address, 0, 16)
+		to := make([]*mail.Address, 0, 16)
 		lt.ForEach(func(k, lv lua.LValue) {
 			if ud, ok := lv.(*lua.LUserData); ok {
 				// TODO should fail if wrong type + test.
 				if entry, ok := unwrapMailAddress(ud); ok {
-					to = append(to, *entry)
+					to = append(to, entry)
 				}
 			}
 		})
diff --git a/pkg/message/manager.go b/pkg/message/manager.go
index 8388251..25dedf9 100644
--- a/pkg/message/manager.go
+++ b/pkg/message/manager.go
@@ -57,20 +57,24 @@ func (s *StoreManager) Deliver(
 	if err != nil {
 		return err
 	}
-	fromaddr, err := enmime.ParseAddressList(header.Get("From"))
-	if err != nil || len(fromaddr) == 0 {
-		fromaddr = make([]*mail.Address, 1)
-		fromaddr[0] = &from.Address
+
+	fromAddrs, err := enmime.ParseAddressList(header.Get("From"))
+	if err != nil || len(fromAddrs) == 0 {
+		// Failed to parse From header, use SMTP MAIL FROM instead.
+		fromAddrs = make([]*mail.Address, 1)
+		fromAddrs[0] = &from.Address
 	}
-	toaddr, err := enmime.ParseAddressList(header.Get("To"))
+
+	toAddrs, err := enmime.ParseAddressList(header.Get("To"))
 	if err != nil {
-		toaddr = make([]*mail.Address, len(recipients))
+		// Failed to parse To header, use SMTP RCPT TO instead.
+		toAddrs = make([]*mail.Address, len(recipients))
 		for i, torecip := range recipients {
-			toaddr[i] = &torecip.Address
+			toAddrs[i] = &torecip.Address
 		}
 	}
-	subject := header.Get("Subject")
 
+	subject := header.Get("Subject")
 	now := time.Now()
 	tstamp := now.UTC().Format(recvdTimeFmt)
 
@@ -79,14 +83,11 @@ func (s *StoreManager) Deliver(
 	for i, recip := range recipients {
 		mailboxes[i] = recip.Mailbox
 	}
-	toAddrs := make([]mail.Address, len(toaddr))
-	for i, addr := range toaddr {
-		toAddrs[i] = *addr
-	}
 
+	// Construct InboundMessage event and process through extensions.
 	inbound := &event.InboundMessage{
 		Mailboxes: mailboxes,
-		From:      *fromaddr[0],
+		From:      fromAddrs[0],
 		To:        toAddrs,
 		Subject:   subject,
 		Size:      int64(len(source)),
@@ -105,13 +106,9 @@ func (s *StoreManager) Deliver(
 	} else {
 		// Event response overrides destination mailboxes and address policy.
 		inbound = extResult
-		toaddr = make([]*mail.Address, len(inbound.To))
-		for i := range inbound.To {
-			toaddr[i] = &inbound.To[i]
-		}
 	}
 
-	// Deliver to mailboxes.
+	// Deliver to each mailbox.
 	for _, mb := range inbound.Mailboxes {
 		// Append recipient and timestamp to generated Recieved header.
 		recvd := fmt.Sprintf("%s  for <%s>; %s\r\n", recvdHeader, mb, tstamp)
@@ -121,8 +118,8 @@ func (s *StoreManager) Deliver(
 		delivery := &Delivery{
 			Meta: event.MessageMetadata{
 				Mailbox: mb,
-				From:    &inbound.From,
-				To:      toaddr,
+				From:    inbound.From,
+				To:      inbound.To,
 				Date:    now,
 				Subject: inbound.Subject,
 			},


Test patch:
diff --git a/pkg/extension/luahost/bind_inboundmessage_test.go b/pkg/extension/luahost/bind_inboundmessage_test.go
index 715f4b3..657577c 100644
--- a/pkg/extension/luahost/bind_inboundmessage_test.go
+++ b/pkg/extension/luahost/bind_inboundmessage_test.go
@@ -31,8 +31,8 @@ const LuaInit = `
 func TestInboundMessageGetters(t *testing.T) {
 	want := &event.InboundMessage{
 		Mailboxes: []string{"mb1", "mb2"},
-		From:      mail.Address{Name: "name1", Address: "addr1"},
-		To: []mail.Address{
+		From:      &mail.Address{Name: "name1", Address: "addr1"},
+		To: []*mail.Address{
 			{Name: "name2", Address: "addr2"},
 			{Name: "name3", Address: "addr3"},
 		},
@@ -66,8 +66,8 @@ func TestInboundMessageGetters(t *testing.T) {
 func TestInboundMessageSetters(t *testing.T) {
 	want := &event.InboundMessage{
 		Mailboxes: []string{"mb1", "mb2"},
-		From:      mail.Address{Name: "name1", Address: "addr1"},
-		To: []mail.Address{
+		From:      &mail.Address{Name: "name1", Address: "addr1"},
+		To: []*mail.Address{
 			{Name: "name2", Address: "addr2"},
 			{Name: "name3", Address: "addr3"},
 		},
diff --git a/pkg/extension/luahost/lua_test.go b/pkg/extension/luahost/lua_test.go
index c72ddd0..dc16937 100644
--- a/pkg/extension/luahost/lua_test.go
+++ b/pkg/extension/luahost/lua_test.go
@@ -179,8 +179,8 @@ func TestBeforeMessageStored(t *testing.T) {
 	// Event to send.
 	msg := event.InboundMessage{
 		Mailboxes: []string{"one", "two"},
-		From:      mail.Address{Name: "From Name", Address: "from@example.com"},
-		To: []mail.Address{
+		From:      &mail.Address{Name: "From Name", Address: "from@example.com"},
+		To: []*mail.Address{
 			{Name: "To1 Name", Address: "to1@example.com"},
 			{Name: "To2 Name", Address: "to2@example.com"},
 		},
@@ -233,8 +233,8 @@ func TestBeforeMessageStored(t *testing.T) {
 	// Verify response values.
 	want := &event.InboundMessage{
 		Mailboxes: []string{"resone", "restwo"},
-		From:      mail.Address{Name: "Res From", Address: "res@example.com"},
-		To: []mail.Address{
+		From:      &mail.Address{Name: "Res From", Address: "res@example.com"},
+		To: []*mail.Address{
 			{Name: "To1 Res", Address: "res1@example.com"},
 			{Name: "To2 Res", Address: "res2@example.com"},
 		},
diff --git a/pkg/message/manager_test.go b/pkg/message/manager_test.go
index 65d44c7..f2ae1a0 100644
--- a/pkg/message/manager_test.go
+++ b/pkg/message/manager_test.go
@@ -137,8 +137,8 @@ test email`),
 
 	require.NotNil(t, got, "BeforeMessageStored listener did not receive InboundMessage")
 	assert.Equal(t, []string{"u1@example.com", "u2@example.com"}, got.Mailboxes, "Mailboxes not equal")
-	assert.Equal(t, mail.Address{Name: "", Address: "from@example.com"}, got.From, "From not equal")
-	assert.Equal(t, []mail.Address{
+	assert.Equal(t, &mail.Address{Name: "", Address: "from@example.com"}, got.From, "From not equal")
+	assert.Equal(t, []*mail.Address{
 		{Name: "", Address: "u1@example.com"},
 		{Name: "", Address: "u3@external.com"},
 	}, got.To, "To not equal")
@@ -173,8 +173,8 @@ func TestDeliverEmitsBeforeMessageStoredEventRcptTo(t *testing.T) {
 
 	require.NotNil(t, got, "BeforeMessageStored listener did not receive InboundMessage")
 	assert.Equal(t, []string{"u1@example.com", "u2@example.com"}, got.Mailboxes, "Mailboxes not equal")
-	assert.Equal(t, mail.Address{Name: "", Address: "from@example.com"}, got.From, "From not equal")
-	assert.Equal(t, []mail.Address{
+	assert.Equal(t, &mail.Address{Name: "", Address: "from@example.com"}, got.From, "From not equal")
+	assert.Equal(t, []*mail.Address{
 		{Name: "", Address: "u1@example.com"},
 		{Name: "", Address: "u2@example.com"},
 	}, got.To, "To not equal")
@@ -256,10 +256,10 @@ func TestDeliverUsesBeforeMessageStoredEventResponseFields(t *testing.T) {
 		func(msg event.InboundMessage) *event.InboundMessage {
 			// Listener rewrites destination mailboxes.
 			msg.Subject = "event subj"
-			msg.From = mail.Address{Address: "from@event.com", Name: "From Event"}
+			msg.From = &mail.Address{Address: "from@event.com", Name: "From Event"}
 
 			// Changing To does not affect destination mailbox(es).
-			msg.To = []mail.Address{
+			msg.To = []*mail.Address{
 				{Address: "to@event.com", Name: "To Event"},
 				{Address: "to2@event.com", Name: "To 2 Event"},
 			}
@@ -479,6 +479,17 @@ test email`
 	assert.Contains(t, got, msgSource, "Source should contain original message source")
 }
 
+func TestMailboxForAddress(t *testing.T) {
+	// Configured for FullNaming.
+	sm, _ := testStoreManager()
+
+	addr := "u1@example.com"
+	got, err := sm.MailboxForAddress(addr)
+	require.NoError(t, err)
+
+	assert.Equal(t, addr, got, "FullNaming mode should return a full address for mailbox")
+}
+
 // Returns an empty StoreManager and extension Host pair, configured for testing.
 func testStoreManager() (*message.StoreManager, *extension.Host) {
 	extHost := extension.NewHost()