fix: email truncation to preserve domain and enforce max width (#606)

ritikaa1802 and drew created

Co-authored-by: drew <me@andrinoff.com>

Change summary

tui/inbox.go      | 27 +++++++++++++++++++++------
tui/inbox_test.go | 28 ++++++++++++++++++++++++++++
2 files changed, 49 insertions(+), 6 deletions(-)

Detailed changes

tui/inbox.go 🔗

@@ -211,14 +211,29 @@ func parseSenderName(from string) string {
 
 // truncateEmail shortens an email for display
 func truncateEmail(email string) string {
-	parts := strings.Split(email, "@")
-	if len(parts) >= 1 && len(parts[0]) > 8 {
-		return parts[0][:8] + "..."
+	maxLength := 18
+
+	if len(email) <= maxLength {
+		return email
 	}
-	if len(parts) >= 1 {
-		return parts[0]
+
+	parts := strings.SplitN(email, "@", 2)
+	if len(parts) != 2 {
+		if len(email) > maxLength {
+			return email[:maxLength-3] + "..."
+		}
+		return email
 	}
-	return email
+
+	local := parts[0]
+	domain := parts[1]
+
+	// Keep full domain visible (e.g. ...@gmail.com) and truncate local part first.
+	if len(local) > 8 {
+		return local[:8] + "...@" + domain
+	}
+
+	return local + "@" + domain
 }
 
 // AccountTab represents a tab for an account

tui/inbox_test.go 🔗

@@ -314,3 +314,31 @@ func TestFetchMoreTriggeredAtListEnd(t *testing.T) {
 		t.Fatalf("expected Limit %d, got %d", expectedLimit, fetchMsg.Limit)
 	}
 }
+
+func TestTruncateEmailKeepsDomain(t *testing.T) {
+	tests := []struct {
+		name  string
+		email string
+		want  string
+	}{
+		{
+			name:  "long local part keeps full domain",
+			email: "verylongemail@gmail.com",
+			want:  "verylong...@gmail.com",
+		},
+		{
+			name:  "short email unchanged",
+			email: "abc@gmail.com",
+			want:  "abc@gmail.com",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := truncateEmail(tt.email)
+			if got != tt.want {
+				t.Fatalf("truncateEmail(%q) = %q, want %q", tt.email, got, tt.want)
+			}
+		})
+	}
+}