Skip to main content

src/internal/encoder/idna.gleam

//// Encode domain parts using Internationalized Domain Names for Applications
//// (IDNA).
////
//// See the following link for reference:
//// - <https://www.rfc-editor.org/rfc/rfc5890>

import gleam/result
import gleam/string

import glidna

import internal/encoder/encoding

/// Encode an email address according to IDNA encoding.
///
/// It leaves the local part as is, and only encodes the domain part.
/// If `mode` is `Utf8`, it will also leave the domain part as is.
pub fn encode_email_address(
  email address: String,
  with mode: encoding.EncodingMode,
) -> Result(String, encoding.EncoderError) {
  address
  |> string.reverse
  |> string.split_once("@")
  |> result.replace_error(encoding.InvalidEmailAddress(address))
  |> result.try(fn(parts) {
    let #(domain, local) = parts

    domain
    |> string.reverse
    |> encode_domain(mode)
    |> result.map(fn(domain) { string.reverse(local) <> "@" <> domain })
  })
  |> result.replace_error(encoding.InvalidEmailAddress(address))
}

pub fn encode_domain(
  domain domain: String,
  with mode: encoding.EncodingMode,
) -> Result(String, encoding.EncoderError) {
  case mode {
    encoding.Ascii ->
      glidna.to_ascii(domain)
      |> result.replace_error(encoding.InvalidDomain(domain))
    encoding.Utf8 -> Ok(domain)
  }
}