diff --git a/components/email/__tests__/recipient-popover.test.tsx b/components/email/__tests__/recipient-popover.test.tsx
new file mode 100644
index 000000000..9a5306720
--- /dev/null
+++ b/components/email/__tests__/recipient-popover.test.tsx
@@ -0,0 +1,39 @@
+import { fireEvent, render, screen } from '@testing-library/react';
+import { afterEach, describe, expect, it } from 'vitest';
+import React from 'react';
+import { RecipientPopover } from '../recipient-popover';
+import { useContactStore } from '@/stores/contact-store';
+import type { ContactCard } from '@/lib/jmap/types';
+
+// A saved contact without a name made the popover show only the address,
+// even though the message header named the sender.
+
+const address = 'wordpress@example.org';
+
+function setContacts(contacts: ContactCard[]) {
+ useContactStore.setState({ contacts });
+}
+
+function openPopover() {
+ render();
+ fireEvent.click(screen.getByRole('button', { name: 'WordPress' }));
+}
+
+describe('RecipientPopover', () => {
+ afterEach(() => setContacts([]));
+
+ it('shows the header name and the address when a matching contact has no name', () => {
+ setContacts([{ id: 'c1', emails: { e1: { address } } } as unknown as ContactCard]);
+ openPopover();
+ const header = screen.getAllByText('WordPress');
+ expect(header.length).toBe(2);
+ expect(screen.getByText(address)).toBeTruthy();
+ });
+
+ it('prefers the contact name over the header name', () => {
+ setContacts([{ id: 'c1', name: { full: 'WP Blog' }, emails: { e1: { address } } } as unknown as ContactCard]);
+ openPopover();
+ expect(screen.getByText('WP Blog')).toBeTruthy();
+ expect(screen.getByText(address)).toBeTruthy();
+ });
+});
diff --git a/components/email/recipient-popover.tsx b/components/email/recipient-popover.tsx
index 09c53bb8f..929aa84c2 100644
--- a/components/email/recipient-popover.tsx
+++ b/components/email/recipient-popover.tsx
@@ -37,8 +37,13 @@ export function RecipientPopover({ name, email, displayLabel, onViewContact, cla
);
});
- const contactName = contact ? getContactDisplayName(contact) : name;
const emails = contact?.emails ? Object.values(contact.emails) : [];
+ // A contact without a name falls back to its address; prefer the name from
+ // the message header in that case.
+ const contactDisplayName = contact ? getContactDisplayName(contact) : '';
+ const contactHasName = !!contactDisplayName &&
+ !emails.some((e) => e.address.toLowerCase() === contactDisplayName.toLowerCase());
+ const contactName = (contactHasName ? contactDisplayName : name) || contactDisplayName;
const phones = contact?.phones ? Object.values(contact.phones) : [];
const orgs = contact?.organizations ? Object.values(contact.organizations) : [];
@@ -160,7 +165,7 @@ export function RecipientPopover({ name, email, displayLabel, onViewContact, cla
{contactName || shownEmail}
- {contactName && contactName !== email && (
+ {contactName && contactName.toLowerCase() !== email.toLowerCase() && (
{shownEmail}