Bug 318495 - Add possibility to create an identity label that will be appended 'name <email>' on display. ui-r=Paenglab, r=mkmelin, r=IanN, a=IanN
authoraceman <acelists@atlas.sk>
Mon, 14 Nov 2016 00:21:21 +0100
changeset 20697 d2c25fee0909d3f8122a97688e390915961029f2
parent 20696 8898cabfdac3e4744a8aeca8b82bc879f701dbde
child 20698 9d31ee8ebb34089fe82ca05e8d0c24a5cacdf1f6
push id12525
push useracelists@atlas.sk
push dateSun, 13 Nov 2016 23:23:00 +0000
treeherdercomm-central@26d7f9ff1aba [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersPaenglab, mkmelin, IanN, IanN
bugs318495
Bug 318495 - Add possibility to create an identity label that will be appended 'name <email>' on display. ui-r=Paenglab, r=mkmelin, r=IanN, a=IanN
mail/components/compose/content/MsgComposeCommands.js
mail/components/compose/content/addressingWidgetOverlay.js
mail/locales/en-US/chrome/messenger/am-identity-edit.dtd
mail/test/mozmill/composition/test-newmsg-compose-identity.js
mailnews/base/prefs/content/am-identity-edit.js
mailnews/base/prefs/content/am-identity-edit.xul
mailnews/base/public/nsIMsgIdentity.idl
mailnews/base/util/nsMsgIdentity.cpp
mailnews/import/becky/src/nsBeckySettings.cpp
mailnews/import/oexpress/nsOESettings.cpp
mailnews/import/outlook/src/nsOutlookCompose.cpp
mailnews/import/outlook/src/nsOutlookSettings.cpp
mailnews/import/winlivemail/nsWMSettings.cpp
suite/locales/en-US/chrome/mailnews/pref/am-identity-edit.dtd
suite/mailnews/compose/MsgComposeCommands.js
suite/mailnews/compose/addressingWidgetOverlay.js
--- a/mail/components/compose/content/MsgComposeCommands.js
+++ b/mail/components/compose/content/MsgComposeCommands.js
@@ -2497,19 +2497,19 @@ function ComposeStartup(aParams)
         gBodyFromArgs = true;
         composeFields.body = args.body;
       }
     }
   }
 
   gComposeType = params.type;
 
-  // " <>" is an empty identity, and most likely not valid
-  if (!params.identity || params.identity.identityName == " <>") {
-    // no pre selected identity, so use the default account
+  // An identity with no email is likely not valid.
+  if (!params.identity || !params.identity.email) {
+    // No pre-selected identity, so use the default account.
     let identities = MailServices.accounts.defaultAccount.identities;
     if (identities.length == 0)
       identities = MailServices.accounts.allIdentities;
     params.identity = identities.queryElementAt(0, Components.interfaces.nsIMsgIdentity);
   }
 
   identityList.selectedItem =
     identityList.getElementsByAttribute("identitykey", params.identity.key)[0];
@@ -3658,20 +3658,18 @@ function FillIdentityList(menulist)
         menulist.menupopup.appendChild(separator);
       }
       accountHadSeparator = needSeparator;
     }
     firstAccountWithIdentities = false;
 
     for (let i = 0; i < identities.length; i++) {
       let identity = identities[i];
-      let address = MailServices.headerParser.makeMailboxObject(
-        identity.fullName, identity.email).toString();
       let item = menulist.appendItem(identity.identityName,
-                                     address,
+                                     identity.fullAddress,
                                      account.incomingServer.prettyName);
       item.setAttribute("identitykey", identity.key);
       item.setAttribute("accountkey", account.key);
       if (i == 0) {
         // Mark the first identity as default.
         item.setAttribute("default", "true");
       }
     }
@@ -4521,17 +4519,20 @@ function LoadIdentity(startup)
           event.initEvent('compose-from-changed', false, true);
           document.getElementById("msgcomposeWindow").dispatchEvent(event);
         }
 
       if (!startup) {
           if (getPref("mail.autoComplete.highlightNonMatches"))
             document.getElementById('addressCol2#1').highlightNonMatches = true;
 
-          addRecipientsToIgnoreList(gCurrentIdentity.identityName);  // only do this if we aren't starting up....it gets done as part of startup already
+          // Only do this if we aren't starting up...
+          // It gets done as part of startup already.
+          addRecipientsToIgnoreList(gCurrentIdentity.fullAddress);
+
           // If the From field is editable, reset the address from the identity.
           if (identityElement.editable)
           {
             identityElement.value = identityElement.selectedItem.value;
             identityElement.inputField.placeholder = getComposeBundle().getFormattedString("msgIdentityPlaceholder", [identityElement.selectedItem.value]);
           }
       }
     }
--- a/mail/components/compose/content/addressingWidgetOverlay.js
+++ b/mail/components/compose/content/addressingWidgetOverlay.js
@@ -231,18 +231,19 @@ function CompFields2Recipients(msgCompFi
       awSetInputAndPopup(msgFollowupTo, "addr_followup", newListBoxNode, templateNode);
 
     // If it's a new message, we need to add an extra empty recipient.
     if (!havePrimaryRecipient)
       _awSetInputAndPopup("", "addr_to", newListBoxNode, templateNode);
     awFitDummyRows(2);
 
     // CompFields2Recipients is called whenever a user replies or edits an existing message. We want to
-    // add all of the recipients for this message to the ignore list for spell check
-    addRecipientsToIgnoreList((gCurrentIdentity ? gCurrentIdentity.identityName + ', ' : '') + msgTo + ', ' + msgCC + ', ' + msgBCC);
+    // add all of the non-empty recipients for this message to the ignore list for spell check
+    let currentAddress = gCurrentIdentity ? gCurrentIdentity.fullAddress : "";
+    addRecipientsToIgnoreList([currentAddress,msgTo,msgCC,msgBCC].filter(adr => adr).join(", "));
   }
 }
 
 function awSetInputAndPopupId(inputElem, popupElem, rowNumber)
 {
   popupElem.id = "addressCol1#" + rowNumber;
   inputElem.id = "addressCol2#" + rowNumber;
   inputElem.setAttribute("aria-labelledby", popupElem.id);
--- a/mail/locales/en-US/chrome/messenger/am-identity-edit.dtd
+++ b/mail/locales/en-US/chrome/messenger/am-identity-edit.dtd
@@ -6,8 +6,13 @@
      equal to the value of accountManager.size entity minus the value
      of accountTree.width entity. -->
 <!ENTITY identityDialog.style "min-width: 75ch;">
 <!ENTITY identityListDesc.label "Configure the settings for this identity:">
 
 <!ENTITY settingsTab.label       "Settings">
 <!ENTITY copiesFoldersTab.label "Copies &amp; Folders">
 <!ENTITY addressingTab.label    "Composition &amp; Addressing">
+
+<!ENTITY publicData.label        "Public Data">
+<!ENTITY privateData.label       "Private Data">
+<!ENTITY identityAlias.label     "Identity Label:">
+<!ENTITY identityAlias.accesskey "b">
--- a/mail/test/mozmill/composition/test-newmsg-compose-identity.js
+++ b/mail/test/mozmill/composition/test-newmsg-compose-identity.js
@@ -20,16 +20,21 @@ var gDrafts;
 var account;
 
 var identityKey1;
 var identity1Email = "x@example.invalid";
 var identityKey2;
 var identity2Email = "y@example.invalid";
 var identity2Name = "User Y";
 var identity2From = identity2Name + " <" + identity2Email + ">";
+var identityKey3;
+var identity3Email = "z@example.invalid";
+var identity3Name = "User Z";
+var identity3Label = "Label Z";
+var identityKey4;
 
 function setupModule(module) {
   for (let lib of MODULE_REQUIRES) {
     collector.getModule(lib).installInto(module);
   }
 
   // Now set up an account with some identities.
   let acctMgr = MailServices.accounts;
@@ -43,16 +48,28 @@ function setupModule(module) {
   identityKey1 = identity1.key;
 
   let identity2 = acctMgr.createIdentity();
   identity2.email = identity2Email;
   identity2.fullName = identity2Name;
   account.addIdentity(identity2);
   identityKey2 = identity2.key;
 
+  let identity3 = acctMgr.createIdentity();
+  identity3.email = identity3Email;
+  identity3.fullName = identity3Name;
+  identity3.label = identity3Label;
+  account.addIdentity(identity3);
+  identityKey3 = identity3.key;
+
+  // Identity with no data.
+  let identity4 = acctMgr.createIdentity();
+  account.addIdentity(identity4);
+  identityKey4 = identity4.key;
+
   gInbox = account.incomingServer.rootFolder
                   .getFolderWithFlags(Ci.nsMsgFolderFlags.Inbox);
   gDrafts = get_special_folder(Ci.nsMsgFolderFlags.Drafts, true);
 }
 
 /**
  * Helper to check that a suitable From identity was set up in the given
  * composer window.
@@ -93,17 +110,17 @@ function test_compose_from_composer() {
   // Compose a new message from the compose window.
   plan_for_new_window("msgcompose");
   mainCompWin.keypress(null, "n", {shiftKey: false, accelKey: true});
   let newCompWin = wait_for_compose_window();
   checkCompIdentity(newCompWin, account.defaultIdentity.key);
   close_compose_window(newCompWin);
 
   // Switch to identity2 in the main compose window, new compose windows
-  // starting from here should use the same identiy as its "parent".
+  // starting from here should use the same identity as its "parent".
   let identityList = mainCompWin.e("msgIdentity");
   identityList.selectedIndex++;
   mainCompWin.click_menus_in_sequence(mainCompWin.e("msgIdentityPopup"),
                                       [ { identitykey: identityKey2 } ]);
   checkCompIdentity(mainCompWin, identityKey2);
 
   // Compose a second new message from the compose window.
   plan_for_new_window("msgcompose");
@@ -120,17 +137,17 @@ function test_compose_from_composer() {
  * Bug 87987
  * Test editing the identity email/name for the current composition.
  */
 function test_editing_identity() {
   Services.prefs.setBoolPref("mail.compose.warned_about_customize_from", true);
   be_in_folder(gInbox);
 
   let compWin = open_compose_new_mail();
-  checkCompIdentity(compWin, account.defaultIdentity.key, " <" + identity1Email + ">");
+  checkCompIdentity(compWin, account.defaultIdentity.key, identity1Email);
 
   // Input custom identity data into the From field.
   let customName = "custom";
   let customEmail = "custom@edited.invalid";
   let identityCustom = customName + " <" + customEmail + ">";
 
   compWin.click_menus_in_sequence(compWin.e("msgIdentityPopup"),
                                   [ { command: "cmd_customizeFromAddress" } ]);
@@ -158,15 +175,58 @@ function test_editing_identity() {
   let curMessage = select_click_row(0);
   assert_equals(curMessage.author, identityCustom);
   // Remove the saved draft.
   press_delete(mc);
   */
   Services.prefs.setBoolPref("mail.compose.warned_about_customize_from", false);
 }
 
+/**
+ * Bug 318495
+ * Test how an identity displays and behaves in the compose window.
+ */
+function test_display_of_identities() {
+  be_in_folder(gInbox);
+
+  let cwc = open_compose_new_mail();
+  checkCompIdentity(cwc, account.defaultIdentity.key, identity1Email);
+
+  cwc.click(cwc.eid("msgIdentity"));
+  cwc.click_menus_in_sequence(cwc.e("msgIdentityPopup"),
+                              [ { identitykey: identityKey2 } ]);
+  checkCompIdentity(cwc, identityKey2, identity2From, identity2From);
+
+  cwc.click(cwc.eid("msgIdentity"));
+  cwc.click_menus_in_sequence(cwc.e("msgIdentityPopup"),
+                              [ { identitykey: identityKey4 } ]);
+  checkCompIdentity(cwc, identityKey4, "[nsIMsgIdentity: " + identityKey4 + "]");
+
+  cwc.click(cwc.eid("msgIdentity"));
+  cwc.click_menus_in_sequence(cwc.e("msgIdentityPopup"),
+                              [ { identitykey: identityKey3 } ]);
+  let identity3From = identity3Name + " <" + identity3Email + ">";
+  checkCompIdentity(cwc, identityKey3,
+                    identity3From + " (" + identity3Label + ")",
+                    identity3From);
+
+  // Bug 1152045, check that the email address from the selected identity
+  // is properly used for the From field in the created message.
+  cwc.window.SaveAsDraft();
+  close_compose_window(cwc);
+
+  be_in_folder(gDrafts);
+  let curMessage = select_click_row(0);
+  assert_equals(curMessage.author, identity3From);
+  // Remove the saved draft.
+  press_delete(mc);
+}
+
 function teardownModule(module) {
   account.removeIdentity(MailServices.accounts.getIdentity(identityKey1));
+  account.removeIdentity(MailServices.accounts.getIdentity(identityKey2));
+  account.removeIdentity(MailServices.accounts.getIdentity(identityKey3));
+
   // The last identity of an account can't be removed so clear all its prefs
   // which effectively destroys it.
-  MailServices.accounts.getIdentity(identityKey2).clearAllValues();
+  MailServices.accounts.getIdentity(identityKey4).clearAllValues();
   MailServices.accounts.removeAccount(account);
 }
--- a/mailnews/base/prefs/content/am-identity-edit.js
+++ b/mailnews/base/prefs/content/am-identity-edit.js
@@ -64,16 +64,21 @@ function initIdentityValues(identity)
     document.getElementById('identity.htmlSigFormat').checked = identity.htmlSigFormat;
 
     if (identity.signature)
       document.getElementById('identity.signature').value = identity.signature.path;
 
     document.getElementById('identity.attachVCard').checked = identity.attachVCard;
     document.getElementById('identity.escapedVCard').value = identity.escapedVCard;
     initSmtpServer(identity.smtpServerKey);
+
+    // This field does not exist for the default identity shown in the am-main.xul pane.
+    let idLabel = document.getElementById("identity.label");
+    if (idLabel)
+      idLabel.value = identity.label;
   }
   else
   {
     // We're adding an identity, use the best default we have.
     initSmtpServer(gAccount.defaultIdentity.smtpServerKey);
   }
 
   setupSignatureItems();
@@ -182,16 +187,19 @@ function validEmailAddress()
 
   return true;
 }
 
 function saveIdentitySettings(identity)
 {
   if (identity)
   {
+    let idLabel = document.getElementById('identity.label');
+    if (idLabel)
+      identity.label = idLabel.value;
     identity.fullName = document.getElementById('identity.fullName').value;
     identity.email = document.getElementById('identity.email').value;
     identity.replyTo = document.getElementById('identity.replyTo').value;
     identity.organization = document.getElementById('identity.organization').value;
     identity.attachSignature = document.getElementById('identity.attachSignature').checked;
     identity.htmlSigText = document.getElementById('identity.htmlSigText').value;
     identity.htmlSigFormat = document.getElementById('identity.htmlSigFormat').checked;
 
--- a/mailnews/base/prefs/content/am-identity-edit.xul
+++ b/mailnews/base/prefs/content/am-identity-edit.xul
@@ -43,16 +43,19 @@
       <tab label="&settingsTab.label;"/>
       <tab label="&copiesFoldersTab.label;"/>
       <tab label="&addressingTab.label;"/>
     </tabs>
 
     <tabpanels id="identityTabsPanels" flex="1">
       <!-- Identity Settings Tab -->
       <vbox flex="1" name="settings">
+        <groupbox>
+          <caption label="&publicData.label;"/>
+
         <grid>
           <columns>
             <column/>
             <column flex="1"/>
           </columns>
           <rows>
             <row align="center">
               <label value="&name.label;" control="identity.fullName" accesskey="&name.accesskey;"/>
@@ -102,29 +105,45 @@
         <hbox align="center">
           <checkbox id="identity.attachVCard" label="&attachVCard.label;" flex="1"
                     accesskey="&attachVCard.accesskey;"/>
           <button class="push" name="editVCard" label="&editVCard.label;"
                   accesskey="&editVCard.accesskey;"
                   oncommand="editVCard()"/>
           <label hidden="true" id="identity.escapedVCard"/>
         </hbox>
+        </groupbox>
 
-        <separator class="thin"/>
-        <hbox align="center">
-          <label value="&smtpName.label;" control="identity.smtpServerKey"
-                 accesskey="&smtpName.accesskey;"/>
-          <menulist id="identity.smtpServerKey" flex="1">
-            <menupopup id="smtpPopup">
-              <menuitem value="" label="&smtpDefaultServer.label;" id="useDefaultItem"/>
-              <menuseparator/>
-              <!-- list will be inserted here -->
-            </menupopup>
-          </menulist>
-        </hbox>
+        <groupbox>
+          <caption label="&privateData.label;"/>
+
+          <hbox align="center">
+            <label value="&smtpName.label;"
+                   control="identity.smtpServerKey"
+                   accesskey="&smtpName.accesskey;"/>
+            <menulist id="identity.smtpServerKey" flex="1">
+              <menupopup id="smtpPopup">
+                <menuitem value=""
+                          label="&smtpDefaultServer.label;"
+                          id="useDefaultItem"/>
+                <menuseparator/>
+                <!-- list will be inserted here -->
+              </menupopup>
+            </menulist>
+          </hbox>
+
+          <separator class="thin"/>
+
+          <hbox align="center">
+            <label value="&identityAlias.label;"
+                   accesskey="&identityAlias.accesskey;"
+                   control="identity.label"/>
+            <textbox id="identity.label" flex="1"/>
+          </hbox>
+        </groupbox>
 
         <spacer flex="1"/>
       </vbox>
 
       <!-- Copies & Folders Tab -->
       <vbox flex="1" name="copiesAndFolders" id="copiesAndFolders"/>
 
       <!-- Composition & Addressing Tab -->
--- a/mailnews/base/public/nsIMsgIdentity.idl
+++ b/mailnews/base/public/nsIMsgIdentity.idl
@@ -7,40 +7,51 @@
 #include "nsIFile.idl"
 
 /**
  * This interface contains all the personal outgoing mail information
  * for a given person.
  * Each identity is identified by a key, which is the <id> string in
  * the identity preferences, such as in mail.identity.<id>.replyTo.
  */
-[scriptable, uuid(4a769f39-f8c2-41e6-962a-175a33107578)]
+[scriptable, uuid(9dede9a0-f6fc-4afc-8fc9-a6af52414b3d)]
 interface nsIMsgIdentity : nsISupports {
   /**
    * Internal preferences ID.
    */
   attribute ACString key;
 
   /**
-   * Overriding display name for this identity. If this pref is not set
-   * then this will return some composed string from the fullname and email.
+   * Label describing this identity. May be empty.
    */
-  attribute AString identityName;
+  attribute AString label;
+
+  /**
+   * Pretty display name to identify this specific identity. Will return a
+   * composed string like "fullname <email> (label)".
+   */
+  readonly attribute AString identityName;
 
   /**
    * User's full name, i.e. John Doe.
    */
   attribute AString fullName;
 
   /**
    * User's e-mail address, i.e. john@doe.com.
    */
   attribute ACString email;
 
   /**
+   * Formats fullName and email into the proper string to use as sender:
+   * name <email>
+   */
+  readonly attribute AString fullAddress;
+
+  /**
    * Optional replyTo address, i.e. johnNOSPAM@doe.com.
    */
   attribute AUTF8String replyTo;
 
   /**
    * Optional organization.
    */
   attribute AString organization;
--- a/mailnews/base/util/nsMsgIdentity.cpp
+++ b/mailnews/base/util/nsMsgIdentity.cpp
@@ -10,16 +10,17 @@
 #include "nsMsgCompCID.h"
 #include "nsIRDFService.h"
 #include "nsIRDFResource.h"
 #include "nsRDFCID.h"
 #include "nsMsgFolderFlags.h"
 #include "nsIMsgFolder.h"
 #include "nsIMsgIncomingServer.h"
 #include "nsIMsgAccountManager.h"
+#include "mozilla/mailnews/MimeHeaderParser.h"
 #include "nsMsgBaseCID.h"
 #include "prprf.h"
 #include "nsISupportsPrimitives.h"
 #include "nsMsgUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsArrayUtils.h"
 
@@ -61,39 +62,55 @@ nsMsgIdentity::SetKey(const nsACString& 
 
   rv = prefs->GetBranch("mail.identity.default.", getter_AddRefs(mDefPrefBranch));
   return rv;
 }
 
 nsresult
 nsMsgIdentity::GetIdentityName(nsAString& idName)
 {
-  nsresult rv = GetUnicharAttribute("identityName", idName);
-  if (NS_FAILED(rv)) return rv;
-
-  if (idName.IsEmpty()) {
-    nsString fullName;
-    rv = GetFullName(fullName);
-    if (NS_FAILED(rv)) return rv;
+  idName.AssignLiteral("");
+  // Try to use "fullname <email>" as the name.
+  nsresult rv = GetFullAddress(idName);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-    nsCString email;
-    rv = GetEmail(email);
-    if (NS_FAILED(rv)) return rv;
-
-    idName.Assign(fullName);
-    idName.AppendLiteral(" <");
-    idName.Append(NS_ConvertASCIItoUTF16(email));
-    idName.AppendLiteral(">");
+  // If a non-empty label exists, append it.
+  nsString label;
+  rv = GetLabel(label);
+  if (NS_SUCCEEDED(rv) && !label.IsEmpty())
+  { // TODO: this should be localizable
+    idName.AppendLiteral(" (");
+    idName.Append(label);
+    idName.AppendLiteral(")");
   }
 
-  return rv;
+  if (!idName.IsEmpty())
+    return NS_OK;
+
+  // If we still found nothing to use, use our key.
+  return ToString(idName);
 }
 
-nsresult nsMsgIdentity::SetIdentityName(const nsAString& idName) {
-  return SetUnicharAttribute("identityName", idName);
+nsresult
+nsMsgIdentity::GetFullAddress(nsAString& fullAddress)
+{
+  nsAutoString fullName;
+  nsresult rv = GetFullName(fullName);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoCString email;
+  rv = GetEmail(email);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (fullName.IsEmpty() && email.IsEmpty())
+    fullAddress.Truncate();
+  else
+    mozilla::mailnews::MakeMimeAddress(fullName, NS_ConvertASCIItoUTF16(email), fullAddress);
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMsgIdentity::ToString(nsAString& aResult)
 {
   aResult.AssignLiteral("[nsIMsgIdentity: ");
   aResult.Append(NS_ConvertASCIItoUTF16(mKey));
   aResult.AppendLiteral("]");
@@ -132,16 +149,17 @@ nsMsgIdentity::ClearAllValues()
 
   return mPrefBranch->DeleteBranch("");
 }
 
 NS_IMPL_IDPREF_STR(EscapedVCard, "escapedVCard")
 NS_IMPL_IDPREF_STR(SmtpServerKey, "smtpServer")
 NS_IMPL_IDPREF_WSTR(FullName, "fullName")
 NS_IMPL_IDPREF_STR(Email, "useremail")
+NS_IMPL_IDPREF_WSTR(Label, "label")
 NS_IMPL_IDPREF_STR(ReplyTo, "reply_to")
 NS_IMPL_IDPREF_WSTR(Organization, "organization")
 NS_IMPL_IDPREF_BOOL(ComposeHtml, "compose_html")
 NS_IMPL_IDPREF_BOOL(AttachVCard, "attach_vcard")
 NS_IMPL_IDPREF_BOOL(AttachSignature, "attach_signature")
 NS_IMPL_IDPREF_WSTR(HtmlSigText, "htmlSigText")
 NS_IMPL_IDPREF_BOOL(HtmlSigFormat, "htmlSigFormat")
 
@@ -565,16 +583,17 @@ NS_IMETHODIMP nsMsgIdentity::GetIntAttri
 
 NS_IMETHODIMP
 nsMsgIdentity::Copy(nsIMsgIdentity *identity)
 {
     NS_ENSURE_ARG_POINTER(identity);
 
     COPY_IDENTITY_BOOL_VALUE(identity,GetComposeHtml,SetComposeHtml)
     COPY_IDENTITY_STR_VALUE(identity,GetEmail,SetEmail)
+    COPY_IDENTITY_WSTR_VALUE(identity,GetLabel,SetLabel)
     COPY_IDENTITY_STR_VALUE(identity,GetReplyTo,SetReplyTo)
     COPY_IDENTITY_WSTR_VALUE(identity,GetFullName,SetFullName)
     COPY_IDENTITY_WSTR_VALUE(identity,GetOrganization,SetOrganization)
     COPY_IDENTITY_STR_VALUE(identity,GetDraftFolder,SetDraftFolder)
     COPY_IDENTITY_STR_VALUE(identity,GetArchiveFolder,SetArchiveFolder)
     COPY_IDENTITY_STR_VALUE(identity,GetFccFolder,SetFccFolder)
     COPY_IDENTITY_BOOL_VALUE(identity,GetFccReplyFollowsParent,
                              SetFccReplyFollowsParent)
--- a/mailnews/import/becky/src/nsBeckySettings.cpp
+++ b/mailnews/import/becky/src/nsBeckySettings.cpp
@@ -370,17 +370,17 @@ nsBeckySettings::CreateIdentity(nsIMsgId
   nsCOMPtr<nsIMsgAccountManager> accountManager =
     do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIMsgIdentity> identity;
   rv = accountManager->CreateIdentity(getter_AddRefs(identity));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  identity->SetIdentityName(NS_ConvertUTF8toUTF16(identityName));
+  identity->SetLabel(NS_ConvertUTF8toUTF16(identityName));
   identity->SetFullName(NS_ConvertUTF8toUTF16(fullName));
   identity->SetEmail(email);
   if (!bccAddress.IsEmpty()) {
     identity->SetDoBcc(true);
     identity->SetDoBccList(bccAddress);
   }
 
   identity.forget(aIdentity);
--- a/mailnews/import/oexpress/nsOESettings.cpp
+++ b/mailnews/import/oexpress/nsOESettings.cpp
@@ -763,18 +763,16 @@ void OESettings::SetIdentities(nsIMsgAcc
                              orgName);
 
   nsCOMPtr<nsIMsgIdentity> id;
   rv = aMgr->CreateIdentity(getter_AddRefs(id));
   if (NS_FAILED(rv))
     return;
 
   id->SetFullName(name);
-  //BUG 470587. Don't set this: id->SetIdentityName(fullName);
-
   id->SetOrganization(orgName);
 
   nsAutoCString nativeEmail;
   NS_CopyUnicodeToNative(email, nativeEmail);
   id->SetEmail(nativeEmail);
   if (!reply.IsEmpty()) {
     nsAutoCString nativeReply;
     NS_CopyUnicodeToNative(reply, nativeReply);
--- a/mailnews/import/outlook/src/nsOutlookCompose.cpp
+++ b/mailnews/import/outlook/src/nsOutlookCompose.cpp
@@ -219,18 +219,17 @@ nsresult nsOutlookCompose::CreateIdentit
   nsCOMPtr<nsIMsgAccountManager> accMgr =
     do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = accMgr->CreateIdentity(&m_pIdentity);
   nsString name;
   name.AssignLiteral("Import Identity");
   if (m_pIdentity) {
     m_pIdentity->SetFullName(name);
-    m_pIdentity->SetIdentityName(name);
-    m_pIdentity->SetEmail(NS_LITERAL_CSTRING("import@import.service"));
+    m_pIdentity->SetEmail(NS_LITERAL_CSTRING("import@service.invalid"));
   }
   return rv;
 }
 
 void nsOutlookCompose::ReleaseIdentity()
 {
   NS_IF_RELEASE(m_pIdentity);
 }
--- a/mailnews/import/outlook/src/nsOutlookSettings.cpp
+++ b/mailnews/import/outlook/src/nsOutlookSettings.cpp
@@ -475,17 +475,16 @@ void OutlookSettings::SetIdentities(nsIM
   nsresult rv;
   nsCOMPtr<nsIMsgIdentity>  id;
   if (!email.IsEmpty() && !name.IsEmpty() && !server.IsEmpty()) {
     // The default identity, nor any other identities matched,
     // create a new one and add it to the account.
     rv = aMgr->CreateIdentity(getter_AddRefs(id));
     if (id) {
       id->SetFullName(name);
-      id->SetIdentityName(name);
       id->SetOrganization(orgName);
 
       nsAutoCString nativeEmail;
       NS_CopyUnicodeToNative(email, nativeEmail);
       id->SetEmail(nativeEmail);
       if (!reply.IsEmpty()) {
         nsAutoCString nativeReply;
         NS_CopyUnicodeToNative(reply, nativeReply);
--- a/mailnews/import/winlivemail/nsWMSettings.cpp
+++ b/mailnews/import/winlivemail/nsWMSettings.cpp
@@ -602,17 +602,16 @@ bool WMSettings::DoNNTPServer(nsIMsgAcco
   return result;
 }
 
 void WMSettings::SetIdentities(nsIMsgAccountManager *pMgr, nsIMsgAccount *pAcc,
                                nsIDOMDocument *xmlDoc, nsAutoString &inUserName,
                                int32_t authMethodIncoming, bool isNNTP)
 {
   // Get the relevant information for an identity
-  // BUG 470587. Don't set this: id->SetIdentityName(fullName);
   nsresult rv;
   nsAutoString value;
 
   nsCOMPtr<nsIMsgIdentity> id;
   rv = pMgr->CreateIdentity(getter_AddRefs(id));
   if (id) {
     IMPORT_LOG0("Created identity and added to the account\n");
     if (NS_SUCCEEDED(nsWMUtils::GetValueForTag(xmlDoc,
--- a/suite/locales/en-US/chrome/mailnews/pref/am-identity-edit.dtd
+++ b/suite/locales/en-US/chrome/mailnews/pref/am-identity-edit.dtd
@@ -6,8 +6,13 @@
      equal to the value of accountManager.size entity minus the value
      of accountTree.width entity. -->
 <!ENTITY identityDialog.style "min-width: 75ch;">
 <!ENTITY identityListDesc.label "Configure the settings for this identity:">
 
 <!ENTITY settingsTab.label       "Settings">
 <!ENTITY copiesFoldersTab.label "Copies &amp; Folders">
 <!ENTITY addressingTab.label    "Composition &amp; Addressing">
+
+<!ENTITY publicData.label        "Public Data">
+<!ENTITY privateData.label       "Private Data">
+<!ENTITY identityAlias.label     "Identity Label:">
+<!ENTITY identityAlias.accesskey "b">
--- a/suite/mailnews/compose/MsgComposeCommands.js
+++ b/suite/mailnews/compose/MsgComposeCommands.js
@@ -1105,18 +1105,18 @@ function ComposeStartup(aParams)
         composeFields.newshost = args.newshost;
       if (args.body)
          composeFields.body = args.body;
     }
   }
 
   gComposeType = params.type;
 
-  // " <>" is an empty identity, and most likely not valid
-  if (!params.identity || params.identity.identityName == " <>") {
+  // An identity with no email is likely not valid.
+  if (!params.identity || !params.identity.email) {
     // no pre selected identity, so use the default account
     var identities = gAccountManager.defaultAccount.identities;
     if (identities.length == 0)
       identities = gAccountManager.allIdentities;
     params.identity = identities.queryElementAt(0, Components.interfaces.nsIMsgIdentity);
   }
 
   identityList.selectedItem =
@@ -2056,21 +2056,18 @@ function FillIdentityList(menulist)
                                          Components.interfaces.nsIMsgIdentity));
 
     if (identities.length == 0)
       continue;
 
     for (let i = 0; i < identities.length; i++)
     {
       let identity = identities[i];
-      let address = MailServices.headerParser
-                                .makeMailboxObject(identity.fullName,
-                                                   identity.email).toString();
       let item = menulist.appendItem(identity.identityName,
-                                     address,
+                                     identity.fullAddress,
                                      account.incomingServer.prettyName);
       item.setAttribute("identitykey", identity.key);
       item.setAttribute("accountkey", account.key);
       if (i == 0)
       {
         // Mark the first identity as default.
         item.setAttribute("default", "true");
       }
@@ -2670,18 +2667,19 @@ function LoadIdentity(startup)
           event.initEvent('compose-from-changed', false, true);
           document.getElementById("msgcomposeWindow").dispatchEvent(event);
         }
 
       if (!startup) {
           if (getPref("mail.autoComplete.highlightNonMatches"))
             document.getElementById('addressCol2#1').highlightNonMatches = true;
 
-          // only do this if we aren't starting up....it gets done as part of startup already
-          addRecipientsToIgnoreList(gCurrentIdentity.identityName);
+          // Only do this if we aren't starting up...
+          // It gets done as part of startup already.
+          addRecipientsToIgnoreList(gCurrentIdentity.fullAddress);
       }
     }
 }
 
 function setupAutocomplete()
 {
   var autoCompleteWidget = document.getElementById("addressCol2#1");
 
--- a/suite/mailnews/compose/addressingWidgetOverlay.js
+++ b/suite/mailnews/compose/addressingWidgetOverlay.js
@@ -203,17 +203,18 @@ function CompFields2Recipients(msgCompFi
 
     // If it's a new message, we need to add an extra empty recipient.
     if (!havePrimaryRecipient)
       _awSetInputAndPopup("", "addr_to", newListBoxNode, templateNode);
     awFitDummyRows(2);
 
     // CompFields2Recipients is called whenever a user replies or edits an existing message.
     // We want to add all of the recipients for this message to the ignore list for spell check
-    addRecipientsToIgnoreList((gCurrentIdentity ? gCurrentIdentity.identityName + ', ' : '') + msgTo + ', ' + msgCC + ', ' + msgBCC);
+    let currentAddress = gCurrentIdentity ? gCurrentIdentity.fullAddress : "";
+    addRecipientsToIgnoreList([currentAddress,msgTo,msgCC,msgBCC].filter(adr => adr).join(", "));
   }
 }
 
 function awSetInputAndPopupId(inputElem, popupElem, rowNumber)
 {
   popupElem.id = "addressCol1#" + rowNumber;
   inputElem.id = "addressCol2#" + rowNumber;
   inputElem.setAttribute("aria-labelledby", popupElem.id);