diff --git a/src/parser/PhutilEmailAddress.php b/src/parser/PhutilEmailAddress.php
index b9a3a44..6acda75 100644
--- a/src/parser/PhutilEmailAddress.php
+++ b/src/parser/PhutilEmailAddress.php
@@ -1,86 +1,114 @@
 <?php
 
 /**
  * Basic email address parser. This parser is very liberal and does not attempt
  * to be fully RFC-compliant, because trying to do so is a crazy mess. However,
  * it should parse all reasonable addresses which are actually in use on the
  * internet today.
  */
 final class PhutilEmailAddress extends Phobject {
 
   private $displayName;
   private $localPart;
   private $domainName;
 
-  public function __construct($email_address) {
+  public function __construct($email_address = null) {
     $email_address = trim($email_address);
 
     $matches = null;
     if (preg_match('/^(.*)<(.*?)>$/', $email_address, $matches)) {
       $display_name = trim($matches[1], '\'" ');
       if (strpos($matches[2], '@') !== false) {
         list($local_part, $domain_name) = explode('@', $matches[2], 2);
       } else {
         $local_part = $matches[2];
         $domain_name = null;
       }
     } else if (preg_match('/^(.*)@(.*)$/', $email_address, $matches)) {
       $display_name = null;
       $local_part = $matches[1];
       $domain_name = $matches[2];
     } else {
       $display_name = null;
       $local_part = $email_address;
       $domain_name = null;
     }
 
     $this->displayName = $display_name;
     $this->localPart = $local_part;
     $this->domainName = $domain_name;
   }
 
   public function __toString() {
     $address = $this->getAddress();
-    if ($this->displayName) {
-      return $this->displayName.' <'.$address.'>';
+    if (strlen($this->displayName)) {
+      $display_name = $this->encodeDisplayName($this->displayName);
+      return $display_name.' <'.$address.'>';
     } else {
       return $address;
     }
   }
 
   public function setDisplayName($display_name) {
     $this->displayName = $display_name;
     return $this;
   }
 
   public function getDisplayName() {
     return $this->displayName;
   }
 
   public function setLocalPart($local_part) {
     $this->localPart = $local_part;
     return $this;
   }
 
   public function getLocalPart() {
     return $this->localPart;
   }
 
   public function setDomainName($domain_name) {
     $this->domainName = $domain_name;
     return $this;
   }
 
   public function getDomainName() {
     return $this->domainName;
   }
 
+  public function setAddress($address) {
+    $parts = explode('@', $address, 2);
+
+    $this->localPart = $parts[0];
+    if (isset($parts[1])) {
+      $this->domainName = $parts[1];
+    }
+
+    return $this;
+  }
+
   public function getAddress() {
     $address = $this->localPart;
-    if ($this->domainName) {
+    if (strlen($this->domainName)) {
       $address .= '@'.$this->domainName;
     }
     return $address;
   }
 
+  private function encodeDisplayName($name) {
+    // NOTE: This is a reasonable effort based on a cursory reading of
+    // RFC2822, but may be significantly misguided.
+
+    // Newlines are not permitted, even when escaped. Discard them.
+    $name = preg_replace("/\s*[\r\n]+\s*/", ' ', $name);
+
+    // Escape double quotes and backslashes.
+    $name = addcslashes($name, '\\"');
+
+    // Quote the string.
+    $name = '"'.$name.'"';
+
+    return $name;
+  }
+
 }
diff --git a/src/parser/__tests__/PhutilEmailAddressTestCase.php b/src/parser/__tests__/PhutilEmailAddressTestCase.php
index b052098..f2c4158 100644
--- a/src/parser/__tests__/PhutilEmailAddressTestCase.php
+++ b/src/parser/__tests__/PhutilEmailAddressTestCase.php
@@ -1,94 +1,130 @@
 <?php
 
 /**
  * Test cases for @{class:PhutilEmailAddress} parser.
  */
 final class PhutilEmailAddressTestCase extends PhutilTestCase {
 
   public function testEmailParsing() {
     $email = new PhutilEmailAddress('Abraham Lincoln <alincoln@logcabin.com>');
     $this->assertEqual(
       'Abraham Lincoln',
       $email->getDisplayName());
     $this->assertEqual(
       'alincoln',
       $email->getLocalPart());
     $this->assertEqual(
       'logcabin.com',
       $email->getDomainName());
     $this->assertEqual(
       'alincoln@logcabin.com',
       $email->getAddress());
 
     $email = new PhutilEmailAddress('alincoln@logcabin.com');
     $this->assertEqual(
       null,
       $email->getDisplayName());
     $this->assertEqual(
       'alincoln',
       $email->getLocalPart());
     $this->assertEqual(
       'logcabin.com',
       $email->getDomainName());
     $this->assertEqual(
       'alincoln@logcabin.com',
       $email->getAddress());
 
     $email = new PhutilEmailAddress('"Abraham" <alincoln@logcabin.com>');
     $this->assertEqual(
       'Abraham',
       $email->getDisplayName());
     $this->assertEqual(
       'alincoln',
       $email->getLocalPart());
     $this->assertEqual(
       'logcabin.com',
       $email->getDomainName());
     $this->assertEqual(
       'alincoln@logcabin.com',
       $email->getAddress());
 
     $email = new PhutilEmailAddress('    alincoln@logcabin.com     ');
     $this->assertEqual(
       null,
       $email->getDisplayName());
     $this->assertEqual(
       'alincoln',
       $email->getLocalPart());
     $this->assertEqual(
       'logcabin.com',
       $email->getDomainName());
     $this->assertEqual(
       'alincoln@logcabin.com',
       $email->getAddress());
 
     $email = new PhutilEmailAddress('alincoln');
     $this->assertEqual(
       null,
       $email->getDisplayName());
     $this->assertEqual(
       'alincoln',
       $email->getLocalPart());
     $this->assertEqual(
       null,
       $email->getDomainName());
     $this->assertEqual(
       'alincoln',
       $email->getAddress());
 
     $email = new PhutilEmailAddress('alincoln <alincoln at logcabin dot com>');
     $this->assertEqual(
       'alincoln',
       $email->getDisplayName());
     $this->assertEqual(
       'alincoln at logcabin dot com',
       $email->getLocalPart());
     $this->assertEqual(
       null,
       $email->getDomainName());
     $this->assertEqual(
       'alincoln at logcabin dot com',
       $email->getAddress());
   }
 
+  public function testEmailEncoding() {
+    $cases = array(
+      array(
+        'Tangerine Q. Hawthorne',
+        'thawthorne@blackspire.bunker',
+        '"Tangerine Q. Hawthorne" <thawthorne@blackspire.bunker>',
+      ),
+      array(
+        'Hector "\\" Backslash',
+        'hector@backslash',
+        '"Hector \\"\\\\\\" Backslash" <hector@backslash>',
+      ),
+      array(
+        'My Middle Name "<name@domain>" Is My Email',
+        'name@domain',
+        '"My Middle Name \\"<name@domain>\\" Is My Email" <name@domain>',
+      ),
+      array(
+        "My Legal Name\nContains A Newline",
+        'newline@example',
+        '"My Legal Name Contains A Newline" <newline@example>',
+      ),
+    );
+
+    foreach ($cases as $case) {
+      list($name, $address, $expect) = $case;
+      $actual = (string)id(new PhutilEmailAddress())
+        ->setDisplayName($name)
+        ->setAddress($address);
+      $this->assertEqual(
+        $expect,
+        $actual,
+        pht('Email: %s + %s -> %s', $name, $address, $expect));
+    }
+  }
+
 }