001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.mail.util;
018
019import javax.mail.internet.InternetAddress;
020import java.net.IDN;
021
022/**
023 * Converts email addresses containing International Domain Names into an ASCII
024 * representation suitable for sending an email.
025 *
026 * @see <a href="https://docs.oracle.com/javase/tutorial/i18n/network/idn.html">https://docs.oracle.com/javase/tutorial/i18n/network/idn.html</a>
027 * @see <a href="https://en.wikipedia.org/wiki/Punycode">https://en.wikipedia.org/wiki/Punycode</a>
028 * @see <a href="https://tools.ietf.org/html/rfc5891">https://tools.ietf.org/html/rfc5891</a>
029 * @see <a href="https://en.wikipedia.org/wiki/Punycode">https://en.wikipedia.org/wiki/Punycode</a>
030 *
031 * @since 1.5
032 */
033public class IDNEmailAddressConverter
034{
035    /**
036     * Convert an email address to its ASCII representation using "Punycode".
037     *
038     * @param email email address.
039     * @return The ASCII representation
040     */
041    public String toASCII(final String email)
042    {
043        final int idx = findAtSymbolIndex(email);
044
045        if (idx < 0)
046        {
047            return email;
048        }
049
050        return getLocalPart(email, idx) + '@' + IDN.toASCII(getDomainPart(email, idx));
051    }
052
053    /**
054     * Convert the address part of an InternetAddress to its Unicode representation.
055     *
056     * @param address email address.
057     * @return The Unicode representation
058     */
059    String toUnicode(final InternetAddress address)
060    {
061        return address != null ? toUnicode(address.getAddress()) : null;
062    }
063
064    /**
065     * Convert an "Punycode" email address to its Unicode representation.
066     *
067     * @param email email address.
068     * @return The Unicode representation
069     */
070    String toUnicode(final String email)
071    {
072        final int idx = findAtSymbolIndex(email);
073
074        if (idx < 0)
075        {
076            return email;
077        }
078
079        return getLocalPart(email, idx) + '@' + IDN.toUnicode(getDomainPart(email, idx));
080    }
081
082    /**
083     * Extracts the local part of the email address.
084     *
085     * @param email email address.
086     * @param idx index of '@' character.
087     * @return local part of email
088     */
089    private String getLocalPart(final String email, final int idx)
090    {
091        return email.substring(0, idx);
092    }
093
094    /**
095     * Extracts the domain part of the email address.
096     *
097     * @param email email address.
098     * @param idx index of '@' character.
099     * @return domain part of email
100     */
101    private String getDomainPart(final String email, final int idx)
102    {
103        return email.substring(idx + 1);
104    }
105
106    /**
107     * Null-safe wrapper for {@link String#indexOf} to find the '@' character.
108     *
109     * @param value String value.
110     * @return index of first '@' character or {@code -1}
111     */
112    private int findAtSymbolIndex(final String value)
113    {
114        if (value == null)
115        {
116            return -1;
117        }
118
119        return value.indexOf('@');
120    }
121}