diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/).
+
+## v0.2.0.0 - 2016-11-12
+
+### Changed
+
+- Changed from the `Text.Email.Validate` module name to `Text.EmailAddress`.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,7 +2,10 @@
 emailaddress
 ============
 
-[![Hackage](https://img.shields.io/hackage/v/emailaddress.svg)](https://hackage.haskell.org/package/emailaddress) [![Build Status](https://secure.travis-ci.org/cdepillabout/emailaddress.svg)](http://travis-ci.org/cdepillabout/emailaddress)
+[![Build Status](https://secure.travis-ci.org/cdepillabout/emailaddress.svg)](http://travis-ci.org/cdepillabout/emailaddress)
+[![Hackage](https://img.shields.io/hackage/v/emailaddress.svg)](https://hackage.haskell.org/package/emailaddress)
+[![Stackage LTS](http://stackage.org/package/emailaddress/badge/lts)](http://stackage.org/lts/package/emailaddress)
+[![Stackage Nightly](http://stackage.org/package/emailaddress/badge/nightly)](http://stackage.org/nightly/package/emailaddress)
 
 This Haskell module wraps around the
 [`email-validate`](https://hackage.haskell.org/package/email-validate) package,
@@ -13,8 +16,8 @@
 [FromJSON](https://hackage.haskell.org/package/aeson/docs/Data-Aeson.html#t:FromJSON).
 This allows us to use the `EmailAddress` type without fear of orphan instances.
 
-This package exposes the module `Text.Email.Validate`, so it can be used as
-a drop-in replacement for
+This package exposes the module `Text.EmailAddress`. It can be used as a
+drop-in replacement for
 [`email-validate`](https://hackage.haskell.org/package/email-validate).
 
 If you would like to add new instances for `EmailAddress`, please send a pull
diff --git a/emailaddress.cabal b/emailaddress.cabal
--- a/emailaddress.cabal
+++ b/emailaddress.cabal
@@ -1,5 +1,5 @@
 name:                emailaddress
-version:             0.1.6.0
+version:             0.2.0.0
 synopsis:            Wrapper around email-validate library adding instances for common type classes.
 description:         Please see README.md
 homepage:            https://github.com/cdepillabout/emailaddress#readme
@@ -11,12 +11,13 @@
 category:            Text
 build-type:          Simple
 extra-source-files:  README.md
+                   , CHANGELOG.md
 cabal-version:       >=1.10
 
 library
   hs-source-dirs:      src
-  exposed-modules:     Text.Email.Validate
-  other-modules:       Text.Email.Validate.Internal
+  exposed-modules:     Text.EmailAddress
+  other-modules:       Text.EmailAddress.Internal
   build-depends:       base >= 4.6 && < 5
                      , aeson >= 0.9
                      , bifunctors >= 5
diff --git a/src/Text/Email/Validate.hs b/src/Text/Email/Validate.hs
deleted file mode 100644
--- a/src/Text/Email/Validate.hs
+++ /dev/null
@@ -1,51 +0,0 @@
-{-|
-Module      : Text.Email.Validate
-Description : Wrapper around email-validate adding additional instances.
-Copyright   : (c) Dennis Gosnell, 2016
-License     : BSD3
-
-This module is a wrapper around
-<https://hackage.haskell.org/package/email-validate-2.2.0/docs/Text-Email-Validate.html Text.Email.Validate>
-from <https://hackage.haskell.org/package/email-validate email-validate>.
-
-This module exports 'EmailAddress', a newtype wrapper around
-<https://hackage.haskell.org/package/email-validate/docs/Text-Email-Validate.html#t:EmailAddress Text.Email.Validate.EmailAddress>.
-Additional instances are defined for our
-new 'EmailAddress', including 'Data.Aeson.ToJSON' and 'Data.Aeson.FromJSON'. This is done so that no
-orphan instances need to be used.
-
-If you would like additional instances to be defined, please send a
-<https://github.com/cdepillabout/emailaddress pull request>.  Additional
-instances will be accepted for any typeclass from any package available on
-stackage.
--}
-
-module Text.Email.Validate
-    ( -- * Data Type
-      EmailAddress
-      -- * Create EmailAddress
-    , emailAddress
-    , validate
-    , emailAddressFromText
-    , validateFromText
-    , emailAddressFromString
-    , validateFromString
-      -- * Check validity
-    , isValid
-      -- * Convert to Text
-    , toText
-      -- * Convert back to ByteString
-    , toByteString
-    , localPart
-    , domainPart
-      -- * Helper functions
-    , canonicalizeEmail
-      -- * Unsafe creation
-    , unsafeEmailAddress
-    ) where
-
-import Text.Email.Validate.Internal
-    ( EmailAddress, canonicalizeEmail, domainPart, emailAddress
-    , emailAddressFromString, emailAddressFromText, isValid, localPart
-    , toByteString, toText, validate, validateFromString, validateFromText
-    , unsafeEmailAddress )
diff --git a/src/Text/Email/Validate/Internal.hs b/src/Text/Email/Validate/Internal.hs
deleted file mode 100644
--- a/src/Text/Email/Validate/Internal.hs
+++ /dev/null
@@ -1,280 +0,0 @@
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE InstanceSigs #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE PackageImports #-}
-
-module Text.Email.Validate.Internal
-    ( EmailAddress(unEmailAddress)
-    , EmailValidate.isValid
-    , EmailValidate.canonicalizeEmail
-    , emailAddress
-    , validate
-    , emailAddressFromText
-    , validateFromText
-    , emailAddressFromString
-    , validateFromString
-    , unsafeEmailAddress
-    , localPart
-    , domainPart
-    , toByteString
-    , toText
-    ) where
-
-import Control.Monad ((<=<))
-import Data.Aeson (FromJSON(..), ToJSON(..), Value(..), withText)
-import Data.Aeson.Types (Parser)
-import Data.Bifunctor (first)
-import Data.ByteString (ByteString)
-import Data.Data (Data)
-import Data.Monoid ((<>))
-import Data.Profunctor (lmap)
-import Data.Profunctor.Product.Default (Default(def))
-import Data.Proxy (Proxy(Proxy))
-import Data.Text (Text, pack)
-import Data.Text.Encoding (decodeUtf8With, encodeUtf8)
-import Data.Text.Encoding.Error (lenientDecode)
-import Database.Persist (PersistField(..), PersistValue)
-import Database.Persist.Sql (PersistFieldSql(..), SqlType)
-import Database.PostgreSQL.Simple.FromField
-    ( Conversion, FieldParser, FromField(..), ResultError(..), returnError )
-import Data.Typeable (Typeable)
-import GHC.Generics (Generic)
-import Opaleye
-    ( Column, Constant(..), PGText, QueryRunnerColumn
-    , QueryRunnerColumnDefault(..) , fieldQueryRunnerColumn )
-import Text.Read (Read(readPrec), ReadPrec)
-import Web.HttpApiData
-    ( FromHttpApiData(parseUrlPiece), ToHttpApiData(toUrlPiece) )
-import Web.PathPieces (PathPiece(fromPathPiece, toPathPiece))
-
-import qualified "email-validate" Text.Email.Validate as EmailValidate
-
--- | Type to represent an email address.  Newtype wrapper around
--- 'EmailValidate.EmailAddress' with additional typeclass instances.
-newtype EmailAddress = EmailAddress
-    { unEmailAddress :: EmailValidate.EmailAddress }
-    deriving (Data, Eq, Generic, Ord, Typeable)
-
-instance Default Constant EmailAddress (Column PGText) where
-    def :: Constant EmailAddress (Column PGText)
-    def = lmap (decodeUtf8With lenientDecode . toByteString) def
-
-instance FromField EmailAddress where
-    fromField :: FieldParser EmailAddress
-    -- fromField :: Field -> Maybe ByteString -> Conversion EmailAddress
-    fromField field Nothing = returnError UnexpectedNull field ""
-    fromField field (Just email) = maybe err return $ emailAddress email
-      where
-        err :: Conversion EmailAddress
-        err = returnError ConversionFailed field $
-            "Could not convert " <> show email <> " to email address"
-
--- | This instance assumes 'EmailAddress' is UTF8-encoded.  See
--- 'validateFromText'.
---
--- >>> import Data.Either (isLeft)
--- >>> fmap toText $ parseUrlPiece "foo@gmail.com"
--- Right "foo@gmail.com"
--- >>> isLeft $ (parseUrlPiece "not an email address" :: Either Text EmailAddress)
--- True
-instance FromHttpApiData EmailAddress where
-    parseUrlPiece :: Text -> Either Text EmailAddress
-    parseUrlPiece = first pack . validateFromText
-
--- | Parse 'EmailAddress' from JSON.
---
--- >>> import Data.Aeson (decode)
--- >>> fmap (fmap toText) (decode "[ \"foo@gmail.com \" ]" :: Maybe [EmailAddress])
--- Just ["foo@gmail.com"]
--- >>> decode "[ \"not an email address\" ]" :: Maybe [EmailAddress]
--- Nothing
-instance FromJSON EmailAddress where
-    parseJSON :: Value -> Parser EmailAddress
-    parseJSON = withText "EmailAddress" $ \t ->
-                    case validate $ encodeUtf8 t of
-                        Left err -> fail $ "Failed to parse email address: " <> err
-                        Right email -> return email
-    {-# INLINE parseJSON #-}
-
--- | See 'emailAddressFromText' and 'toText'.
---
--- >>> fmap toText $ fromPathPiece "foo@gmail.com"
--- Just "foo@gmail.com"
--- >>> fmap toText $ fromPathPiece "this is not an email address"
--- Nothing
--- >>> toPathPiece $ unsafeEmailAddress "foo" "gmail.com"
--- "foo@gmail.com"
-instance PathPiece EmailAddress where
-    fromPathPiece :: Text -> Maybe EmailAddress
-    fromPathPiece = emailAddressFromText
-
-    toPathPiece :: EmailAddress -> Text
-    toPathPiece = toText
-
--- | Treat 'EmailAddress' just like a 'Text' value.
---
--- >>> import Data.Either (isLeft)
--- >>> import Database.Persist.Types (PersistValue(PersistBool, PersistText))
--- >>> toPersistValue $ unsafeEmailAddress "foo" "gmail.com"
--- PersistText "foo@gmail.com"
--- >>> fmap toText $ fromPersistValue (PersistText "foo@gmail.com")
--- Right "foo@gmail.com"
--- >>> isLeft (fromPersistValue (PersistText "not an email address") :: Either Text EmailAddress)
--- True
--- >>> isLeft (fromPersistValue (PersistBool False) :: Either Text EmailAddress)
--- True
-instance PersistField EmailAddress where
-    toPersistValue :: EmailAddress -> PersistValue
-    toPersistValue = toPersistValue . toText
-
-    fromPersistValue :: PersistValue -> Either Text EmailAddress
-    fromPersistValue = first pack . validateFromText <=< fromPersistValue
-
--- | Treat 'EmailAddress' just like a 'Text' value.
---
--- >>> sqlType (Proxy :: Proxy EmailAddress)
--- SqlString
-instance PersistFieldSql EmailAddress where
-    sqlType :: Proxy EmailAddress -> SqlType
-    sqlType _ = sqlType (Proxy :: Proxy Text)
-
-instance QueryRunnerColumnDefault PGText EmailAddress where
-    queryRunnerColumnDefault :: QueryRunnerColumn PGText EmailAddress
-    queryRunnerColumnDefault = fieldQueryRunnerColumn
-
--- |
--- >>> toText $ read "\"foo@gmail.com\""
--- "foo@gmail.com"
-instance Read EmailAddress where
-    readPrec :: ReadPrec EmailAddress
-    readPrec = fmap EmailAddress readPrec
-
--- |
--- >>> show $ unsafeEmailAddress "foo" "gmail.com"
--- "\"foo@gmail.com\""
-instance Show EmailAddress where
-    show :: EmailAddress -> String
-    show = show . unEmailAddress
-
--- | Turn 'EmailAddress' into JSON.
---
--- >>> toJSON $ unsafeEmailAddress "foo" "gmail.com"
--- String "foo@gmail.com"
-instance ToJSON EmailAddress where
-    toJSON :: EmailAddress -> Value
-    toJSON = String . decodeUtf8With lenientDecode . toByteString
-
--- | This instance assumes 'EmailAddress' is UTF8-encoded.  See 'toText'.
---
--- >>> toUrlPiece $ unsafeEmailAddress "foo" "gmail.com"
--- "foo@gmail.com"
-instance ToHttpApiData EmailAddress where
-      toUrlPiece = toText
-
--- | Wrapper around 'EmailValidate.validate'.
---
--- >>> validate "foo@gmail.com"
--- Right "foo@gmail.com"
--- >>> import Data.Either (isLeft)
--- >>> isLeft $ validate "not an email address"
--- True
-validate :: ByteString -> Either String EmailAddress
-validate = fmap EmailAddress . EmailValidate.validate
-
--- | Wrapper around 'EmailValidate.emailAddress'.
---
--- Similar to 'validate', but returns 'Nothing' if the email address fails to
--- parse.
---
--- >>> emailAddress "foo@gmail.com"
--- Just "foo@gmail.com"
--- >>> emailAddress "not an email address"
--- Nothing
-emailAddress :: ByteString -> Maybe EmailAddress
-emailAddress = fmap EmailAddress . EmailValidate.emailAddress
-
--- | Create an 'EmailAddress' from a 'Text' value.  See 'validate'.
-validateFromText :: Text -> Either String EmailAddress
-validateFromText = validate . encodeUtf8
-
--- | Create an 'EmailAddress' from a 'Text' value.  See 'emailAddress'.
-emailAddressFromText :: Text -> Maybe EmailAddress
-emailAddressFromText = emailAddress . encodeUtf8
-
--- | Create an 'EmailAddress' from a 'String' value.  See 'validate'.
-validateFromString :: String -> Either String EmailAddress
-validateFromString = validateFromText . pack
-
--- | Create an 'EmailAddress' from a 'String' value.  See 'emailAddress'.
-emailAddressFromString :: String -> Maybe EmailAddress
-emailAddressFromString = emailAddressFromText . pack
-
--- | Wrapper around 'EmailValidate.unsafeEmailAddress'.
---
--- Unsafely create an 'EmailAddress' from a local part and a domain part.  The
--- first argument is the local part, and the second argument is the domain
--- part.
---
--- For example, in the email address @foo\@gmail.com@, the local part is @foo@
--- and the domain part is @gmail.com@.
---
--- >>> unsafeEmailAddress "foo" "gmail.com"
--- "foo@gmail.com"
-unsafeEmailAddress
-    :: ByteString    -- ^ Local part
-    -> ByteString    -- ^ Domain part
-    -> EmailAddress
-unsafeEmailAddress = (EmailAddress .) . EmailValidate.unsafeEmailAddress
-
--- | Wrapper around 'EmailValidate.localPart'.
---
--- Extracts the local part from an email address.
---
--- For example, in the email address @foo\@gmail.com@, the local part is @foo@.
---
--- >>> let email = unsafeEmailAddress "foo" "gmail.com"
--- >>> email
--- "foo@gmail.com"
--- >>> localPart email
--- "foo"
-localPart :: EmailAddress -> ByteString
-localPart = EmailValidate.localPart . unEmailAddress
-
--- | Wrapper around 'EmailValidate.domainPart'.
---
--- Extracts the domain part from an email address.
---
--- For example, in the email address @foo\@gmail.com@, the domain part is
--- @gmail.com@.
---
--- >>> let email = unsafeEmailAddress "foo" "gmail.com"
--- >>> email
--- "foo@gmail.com"
--- >>> domainPart email
--- "gmail.com"
-domainPart :: EmailAddress -> ByteString
-domainPart = EmailValidate.domainPart . unEmailAddress
-
--- | Wrapper around 'EmailValidate.toByteString'.
---
--- >>> let email = unsafeEmailAddress "foo" "gmail.com"
--- >>> email
--- "foo@gmail.com"
--- >>> toByteString email
--- "foo@gmail.com"
-toByteString :: EmailAddress -> ByteString
-toByteString = EmailValidate.toByteString . unEmailAddress
-
--- | Convert an email address to 'Text'.
---
--- This assumes the 'EmailAddress' is UTF8-encoded.
---
--- >>> let email = unsafeEmailAddress "foo" "gmail.com"
--- >>> email
--- "foo@gmail.com"
--- >>> toText email
--- "foo@gmail.com"
-toText :: EmailAddress -> Text
-toText = decodeUtf8With lenientDecode . toByteString
diff --git a/src/Text/EmailAddress.hs b/src/Text/EmailAddress.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/EmailAddress.hs
@@ -0,0 +1,51 @@
+{-|
+Module      : Text.EmailAddress
+Description : Wrapper around email-validate adding additional instances.
+Copyright   : (c) Dennis Gosnell, 2016
+License     : BSD3
+
+This module is a wrapper around
+<https://hackage.haskell.org/package/email-validate-2.2.0/docs/Text-Email-Validate.html Text.Email.Validate>
+from <https://hackage.haskell.org/package/email-validate email-validate>.
+
+This module exports 'EmailAddress', a newtype wrapper around
+<https://hackage.haskell.org/package/email-validate/docs/Text-Email-Validate.html#t:EmailAddress Text.Email.Validate.EmailAddress>.
+Additional instances are defined for our
+new 'EmailAddress', including 'Data.Aeson.ToJSON' and 'Data.Aeson.FromJSON'. This is done so that no
+orphan instances need to be used.
+
+If you would like additional instances to be defined, please send a
+<https://github.com/cdepillabout/emailaddress pull request>.  Additional
+instances will be accepted for any typeclass from any package available on
+stackage.
+-}
+
+module Text.EmailAddress
+    ( -- * Data Type
+      EmailAddress(EmailAddress, unEmailAddress)
+      -- * Create EmailAddress
+    , emailAddress
+    , validate
+    , emailAddressFromText
+    , validateFromText
+    , emailAddressFromString
+    , validateFromString
+      -- * Check validity
+    , isValid
+      -- * Convert to Text
+    , toText
+      -- * Convert back to ByteString
+    , toByteString
+    , localPart
+    , domainPart
+      -- * Helper functions
+    , canonicalizeEmail
+      -- * Unsafe creation
+    , unsafeEmailAddress
+    ) where
+
+import Text.EmailAddress.Internal
+       (EmailAddress(EmailAddress, unEmailAddress), canonicalizeEmail,
+        domainPart, emailAddress, emailAddressFromString,
+        emailAddressFromText, isValid, localPart, toByteString, toText,
+        validate, validateFromString, validateFromText, unsafeEmailAddress)
diff --git a/src/Text/EmailAddress/Internal.hs b/src/Text/EmailAddress/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/EmailAddress/Internal.hs
@@ -0,0 +1,279 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE InstanceSigs #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+module Text.EmailAddress.Internal
+    ( EmailAddress(EmailAddress, unEmailAddress)
+    , EmailValidate.isValid
+    , EmailValidate.canonicalizeEmail
+    , emailAddress
+    , validate
+    , emailAddressFromText
+    , validateFromText
+    , emailAddressFromString
+    , validateFromString
+    , unsafeEmailAddress
+    , localPart
+    , domainPart
+    , toByteString
+    , toText
+    ) where
+
+import Control.Monad ((<=<))
+import Data.Aeson (FromJSON(..), ToJSON(..), Value(..), withText)
+import Data.Aeson.Types (Parser)
+import Data.Bifunctor (first)
+import Data.ByteString (ByteString)
+import Data.Data (Data)
+import Data.Monoid ((<>))
+import Data.Profunctor (lmap)
+import Data.Profunctor.Product.Default (Default(def))
+import Data.Proxy (Proxy(Proxy))
+import Data.Text (Text, pack)
+import Data.Text.Encoding (decodeUtf8With, encodeUtf8)
+import Data.Text.Encoding.Error (lenientDecode)
+import Database.Persist (PersistField(..), PersistValue)
+import Database.Persist.Sql (PersistFieldSql(..), SqlType)
+import Database.PostgreSQL.Simple.FromField
+    ( Conversion, FieldParser, FromField(..), ResultError(..), returnError )
+import Data.Typeable (Typeable)
+import GHC.Generics (Generic)
+import Opaleye
+    ( Column, Constant(..), PGText, QueryRunnerColumn
+    , QueryRunnerColumnDefault(..) , fieldQueryRunnerColumn )
+import Text.Read (Read(readPrec), ReadPrec)
+import Web.HttpApiData
+    ( FromHttpApiData(parseUrlPiece), ToHttpApiData(toUrlPiece) )
+import Web.PathPieces (PathPiece(fromPathPiece, toPathPiece))
+
+import qualified Text.Email.Validate as EmailValidate
+
+-- | Type to represent an email address.  Newtype wrapper around
+-- 'EmailValidate.EmailAddress' with additional typeclass instances.
+newtype EmailAddress = EmailAddress
+    { unEmailAddress :: EmailValidate.EmailAddress }
+    deriving (Data, Eq, Generic, Ord, Typeable)
+
+instance Default Constant EmailAddress (Column PGText) where
+    def :: Constant EmailAddress (Column PGText)
+    def = lmap (decodeUtf8With lenientDecode . toByteString) def
+
+instance FromField EmailAddress where
+    fromField :: FieldParser EmailAddress
+    -- fromField :: Field -> Maybe ByteString -> Conversion EmailAddress
+    fromField field Nothing = returnError UnexpectedNull field ""
+    fromField field (Just email) = maybe err return $ emailAddress email
+      where
+        err :: Conversion EmailAddress
+        err = returnError ConversionFailed field $
+            "Could not convert " <> show email <> " to email address"
+
+-- | This instance assumes 'EmailAddress' is UTF8-encoded.  See
+-- 'validateFromText'.
+--
+-- >>> import Data.Either (isLeft)
+-- >>> fmap toText $ parseUrlPiece "foo@gmail.com"
+-- Right "foo@gmail.com"
+-- >>> isLeft $ (parseUrlPiece "not an email address" :: Either Text EmailAddress)
+-- True
+instance FromHttpApiData EmailAddress where
+    parseUrlPiece :: Text -> Either Text EmailAddress
+    parseUrlPiece = first pack . validateFromText
+
+-- | Parse 'EmailAddress' from JSON.
+--
+-- >>> import Data.Aeson (decode)
+-- >>> fmap (fmap toText) (decode "[ \"foo@gmail.com \" ]" :: Maybe [EmailAddress])
+-- Just ["foo@gmail.com"]
+-- >>> decode "[ \"not an email address\" ]" :: Maybe [EmailAddress]
+-- Nothing
+instance FromJSON EmailAddress where
+    parseJSON :: Value -> Parser EmailAddress
+    parseJSON = withText "EmailAddress" $ \t ->
+                    case validate $ encodeUtf8 t of
+                        Left err -> fail $ "Failed to parse email address: " <> err
+                        Right email -> return email
+    {-# INLINE parseJSON #-}
+
+-- | See 'emailAddressFromText' and 'toText'.
+--
+-- >>> fmap toText $ fromPathPiece "foo@gmail.com"
+-- Just "foo@gmail.com"
+-- >>> fmap toText $ fromPathPiece "this is not an email address"
+-- Nothing
+-- >>> toPathPiece $ unsafeEmailAddress "foo" "gmail.com"
+-- "foo@gmail.com"
+instance PathPiece EmailAddress where
+    fromPathPiece :: Text -> Maybe EmailAddress
+    fromPathPiece = emailAddressFromText
+
+    toPathPiece :: EmailAddress -> Text
+    toPathPiece = toText
+
+-- | Treat 'EmailAddress' just like a 'Text' value.
+--
+-- >>> import Data.Either (isLeft)
+-- >>> import Database.Persist.Types (PersistValue(PersistBool, PersistText))
+-- >>> toPersistValue $ unsafeEmailAddress "foo" "gmail.com"
+-- PersistText "foo@gmail.com"
+-- >>> fmap toText $ fromPersistValue (PersistText "foo@gmail.com")
+-- Right "foo@gmail.com"
+-- >>> isLeft (fromPersistValue (PersistText "not an email address") :: Either Text EmailAddress)
+-- True
+-- >>> isLeft (fromPersistValue (PersistBool False) :: Either Text EmailAddress)
+-- True
+instance PersistField EmailAddress where
+    toPersistValue :: EmailAddress -> PersistValue
+    toPersistValue = toPersistValue . toText
+
+    fromPersistValue :: PersistValue -> Either Text EmailAddress
+    fromPersistValue = first pack . validateFromText <=< fromPersistValue
+
+-- | Treat 'EmailAddress' just like a 'Text' value.
+--
+-- >>> sqlType (Proxy :: Proxy EmailAddress)
+-- SqlString
+instance PersistFieldSql EmailAddress where
+    sqlType :: Proxy EmailAddress -> SqlType
+    sqlType _ = sqlType (Proxy :: Proxy Text)
+
+instance QueryRunnerColumnDefault PGText EmailAddress where
+    queryRunnerColumnDefault :: QueryRunnerColumn PGText EmailAddress
+    queryRunnerColumnDefault = fieldQueryRunnerColumn
+
+-- |
+-- >>> toText $ read "\"foo@gmail.com\""
+-- "foo@gmail.com"
+instance Read EmailAddress where
+    readPrec :: ReadPrec EmailAddress
+    readPrec = fmap EmailAddress readPrec
+
+-- |
+-- >>> show $ unsafeEmailAddress "foo" "gmail.com"
+-- "\"foo@gmail.com\""
+instance Show EmailAddress where
+    show :: EmailAddress -> String
+    show = show . unEmailAddress
+
+-- | Turn 'EmailAddress' into JSON.
+--
+-- >>> toJSON $ unsafeEmailAddress "foo" "gmail.com"
+-- String "foo@gmail.com"
+instance ToJSON EmailAddress where
+    toJSON :: EmailAddress -> Value
+    toJSON = String . decodeUtf8With lenientDecode . toByteString
+
+-- | This instance assumes 'EmailAddress' is UTF8-encoded.  See 'toText'.
+--
+-- >>> toUrlPiece $ unsafeEmailAddress "foo" "gmail.com"
+-- "foo@gmail.com"
+instance ToHttpApiData EmailAddress where
+      toUrlPiece = toText
+
+-- | Wrapper around 'EmailValidate.validate'.
+--
+-- >>> validate "foo@gmail.com"
+-- Right "foo@gmail.com"
+-- >>> import Data.Either (isLeft)
+-- >>> isLeft $ validate "not an email address"
+-- True
+validate :: ByteString -> Either String EmailAddress
+validate = fmap EmailAddress . EmailValidate.validate
+
+-- | Wrapper around 'EmailValidate.emailAddress'.
+--
+-- Similar to 'validate', but returns 'Nothing' if the email address fails to
+-- parse.
+--
+-- >>> emailAddress "foo@gmail.com"
+-- Just "foo@gmail.com"
+-- >>> emailAddress "not an email address"
+-- Nothing
+emailAddress :: ByteString -> Maybe EmailAddress
+emailAddress = fmap EmailAddress . EmailValidate.emailAddress
+
+-- | Create an 'EmailAddress' from a 'Text' value.  See 'validate'.
+validateFromText :: Text -> Either String EmailAddress
+validateFromText = validate . encodeUtf8
+
+-- | Create an 'EmailAddress' from a 'Text' value.  See 'emailAddress'.
+emailAddressFromText :: Text -> Maybe EmailAddress
+emailAddressFromText = emailAddress . encodeUtf8
+
+-- | Create an 'EmailAddress' from a 'String' value.  See 'validate'.
+validateFromString :: String -> Either String EmailAddress
+validateFromString = validateFromText . pack
+
+-- | Create an 'EmailAddress' from a 'String' value.  See 'emailAddress'.
+emailAddressFromString :: String -> Maybe EmailAddress
+emailAddressFromString = emailAddressFromText . pack
+
+-- | Wrapper around 'EmailValidate.unsafeEmailAddress'.
+--
+-- Unsafely create an 'EmailAddress' from a local part and a domain part.  The
+-- first argument is the local part, and the second argument is the domain
+-- part.
+--
+-- For example, in the email address @foo\@gmail.com@, the local part is @foo@
+-- and the domain part is @gmail.com@.
+--
+-- >>> unsafeEmailAddress "foo" "gmail.com"
+-- "foo@gmail.com"
+unsafeEmailAddress
+    :: ByteString    -- ^ Local part
+    -> ByteString    -- ^ Domain part
+    -> EmailAddress
+unsafeEmailAddress = (EmailAddress .) . EmailValidate.unsafeEmailAddress
+
+-- | Wrapper around 'EmailValidate.localPart'.
+--
+-- Extracts the local part from an email address.
+--
+-- For example, in the email address @foo\@gmail.com@, the local part is @foo@.
+--
+-- >>> let email = unsafeEmailAddress "foo" "gmail.com"
+-- >>> email
+-- "foo@gmail.com"
+-- >>> localPart email
+-- "foo"
+localPart :: EmailAddress -> ByteString
+localPart = EmailValidate.localPart . unEmailAddress
+
+-- | Wrapper around 'EmailValidate.domainPart'.
+--
+-- Extracts the domain part from an email address.
+--
+-- For example, in the email address @foo\@gmail.com@, the domain part is
+-- @gmail.com@.
+--
+-- >>> let email = unsafeEmailAddress "foo" "gmail.com"
+-- >>> email
+-- "foo@gmail.com"
+-- >>> domainPart email
+-- "gmail.com"
+domainPart :: EmailAddress -> ByteString
+domainPart = EmailValidate.domainPart . unEmailAddress
+
+-- | Wrapper around 'EmailValidate.toByteString'.
+--
+-- >>> let email = unsafeEmailAddress "foo" "gmail.com"
+-- >>> email
+-- "foo@gmail.com"
+-- >>> toByteString email
+-- "foo@gmail.com"
+toByteString :: EmailAddress -> ByteString
+toByteString = EmailValidate.toByteString . unEmailAddress
+
+-- | Convert an email address to 'Text'.
+--
+-- This assumes the 'EmailAddress' is UTF8-encoded.
+--
+-- >>> let email = unsafeEmailAddress "foo" "gmail.com"
+-- >>> email
+-- "foo@gmail.com"
+-- >>> toText email
+-- "foo@gmail.com"
+toText :: EmailAddress -> Text
+toText = decodeUtf8With lenientDecode . toByteString
