Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function that parses an RFC5322 email address string #67

Open
Microtribute opened this issue Nov 22, 2021 · 4 comments
Open

Function that parses an RFC5322 email address string #67

Microtribute opened this issue Nov 22, 2021 · 4 comments

Comments

@Microtribute
Copy link

Microtribute commented Nov 22, 2021

I think it would be very handy to have a function that does exactly the opposite action of the renderAddress function. So you give the function an email address (format specified in RFC5322) and the function spits out an Address value.

parseEmailAddress :: ByteString -> Maybe Address
parseEmailAddress email =
      -- function body

Application:

parseEmailAddress "Jon Doe <jon.doe.mail.com>" -- Just (Address (Just "John Doe") "jon.doe@mail.com")

parseEmailAddress "jon.doe@mail.com" -- Just (Address Nothing "jon.doe@mail.com")

parseEmailAddress "jon" -- Nothing

I can't write this function myself as I am new to Haskell.

@Microtribute
Copy link
Author

Microtribute commented Nov 22, 2021

I tried to write the function myself:

{-# LANGUAGE NamedFieldPuns #-}

module Email where

import           Text.Parsec (parse)
import           Text.Parsec.Rfc2822 (NameAddr(..), name_addr)
import           Network.Mail.Mime (Address(..))
import           Data.Text (pack)
import           Data.List (elem)

mapMaybe :: (a -> b) -> Maybe a -> Maybe b
mapMaybe _ Nothing = Nothing
mapMaybe f (Just a) = Just (f a)

-- | Given a string email address, spits out an Address record
parseEmailAddress :: String -> Maybe Address
parseEmailAddress str =
  case parse name_addr "" addr of
    Left _ ->
      Nothing
    Right (NameAddr { nameAddr_name, nameAddr_addr }) ->
      Just (Address (mapMaybe pack nameAddr_name) (pack nameAddr_addr))
  where
    -- Standardize the email address
    addr = if '<' `elem` str then str else "<" ++ str ++ ">"

@psibi
Copy link
Collaborator

psibi commented Nov 22, 2021

Probably you want some variant of check function: https://hackage.haskell.org/package/check-email-1.0.2/docs/Network-Email-Check.html ?

@Microtribute
Copy link
Author

@psibi the function I wrote just returns a Nothing if the email is not valid against the specification.

@kindaro
Copy link
Collaborator

kindaro commented Nov 26, 2021

TLDR   I agree that it would be handy to have a smart constructor like this, but we have a responsibility to do it well or not at all.

The situation is a little unfortunate since we have at least three types for an e-mail address on Hackage: from mime-mail (this repository), from hsemail and from email-validate.

  • It makes sense to have a smart constructor parseAddress compatible with renderAddress and aligned with the standard. Maybe even some quasi-quotes. But, if done the right way, it entails depending on a parser library. So, a major version bump.

  • The specification is tricky. There are subtleties upon subtleties. Writing a parser like this is a hard task. Since this package aims for reliability, I say we should avoid giving promises we cannot deliver upon.

  • Ideally there should be a single email validation package that everyone depends upon. I am not sure why mime-mail does not depend on either of the two packages I linked above in the first place, but instead defines its own type. Both packages have solid test suites and have recent updates. I know that Michael @snoyberg usually has a good reason for decisions like this — for example, maybe he was unhappy with the handling of Unicode in the other two packages.

I think the right way forward is to talk to the maintainers of the libraries linked above (@peti and @Porges) and propose a convergence to a unified type for an e-mail address. Then mime-mail could migrate to that unified type in the next major version. This would be good for the Haskell ecosystem as a whole.

@psibi   What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants