Author: sgoeschl
Date: Mon Feb  1 21:25:23 2016
New Revision: 1728011

URL: http://svn.apache.org/viewvc?rev=1728011&view=rev
Log:
[EMAIL-160] Add Support for International Domain Names

Added:
    commons/proper/email/trunk/.gitignore
    
commons/proper/email/trunk/src/main/java/org/apache/commons/mail/util/IDNEmailAddressConverter.java
    
commons/proper/email/trunk/src/test/java/org/apache/commons/mail/util/IDNEmailAddressConverterTest.java
Modified:
    commons/proper/email/trunk/pom.xml
    commons/proper/email/trunk/src/changes/changes.xml
    commons/proper/email/trunk/src/main/java/org/apache/commons/mail/Email.java
    
commons/proper/email/trunk/src/test/java/org/apache/commons/mail/EmailTest.java

Added: commons/proper/email/trunk/.gitignore
URL: 
http://svn.apache.org/viewvc/commons/proper/email/trunk/.gitignore?rev=1728011&view=auto
==============================================================================
--- commons/proper/email/trunk/.gitignore (added)
+++ commons/proper/email/trunk/.gitignore Mon Feb  1 21:25:23 2016
@@ -0,0 +1,10 @@
+.DS_Store
+*.iml
+*.iws
+*.ipr
+target
+.swp
+.idea
+.classpath
+.project
+.settings

Modified: commons/proper/email/trunk/pom.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/email/trunk/pom.xml?rev=1728011&r1=1728010&r2=1728011&view=diff
==============================================================================
--- commons/proper/email/trunk/pom.xml (original)
+++ commons/proper/email/trunk/pom.xml Mon Feb  1 21:25:23 2016
@@ -292,8 +292,8 @@
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-        <maven.compiler.source>1.5</maven.compiler.source>
-        <maven.compiler.target>1.5</maven.compiler.target>
+        <maven.compiler.source>1.6</maven.compiler.source>
+        <maven.compiler.target>1.6</maven.compiler.target>
         <commons.componentid>email</commons.componentid>
         <commons.jira.id>EMAIL</commons.jira.id>
         <commons.jira.pid>12310474</commons.jira.pid>

Modified: commons/proper/email/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/email/trunk/src/changes/changes.xml?rev=1728011&r1=1728010&r2=1728011&view=diff
==============================================================================
--- commons/proper/email/trunk/src/changes/changes.xml (original)
+++ commons/proper/email/trunk/src/changes/changes.xml Mon Feb  1 21:25:23 2016
@@ -22,7 +22,10 @@
   </properties>
 
   <body>
-    <release version="1.5" date="2015-MM-DD">
+    <release version="1.5" date="2016-MM-DD">
+      <action dev="sgoeschl" type="add" issue="EMAIL-160" date="2016-02-01">
+        Add Support for International Domain Names.
+      </action>
       <action dev="ggregory" type="add" issue="EMAIL-154" date="2015-07-26" 
due-to="Ken Geis, Balachandran Sivakumar">
         Add Email#getHeader(String) and Email#getHeaders() methods.
       </action>

Modified: 
commons/proper/email/trunk/src/main/java/org/apache/commons/mail/Email.java
URL: 
http://svn.apache.org/viewvc/commons/proper/email/trunk/src/main/java/org/apache/commons/mail/Email.java?rev=1728011&r1=1728010&r2=1728011&view=diff
==============================================================================
--- commons/proper/email/trunk/src/main/java/org/apache/commons/mail/Email.java 
(original)
+++ commons/proper/email/trunk/src/main/java/org/apache/commons/mail/Email.java 
Mon Feb  1 21:25:23 2016
@@ -41,6 +41,8 @@ import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
 
+import org.apache.commons.mail.util.IDNEmailAddressConverter;
+
 /**
  * The base class for all email messages.  This class sets the
  * sender's email &amp; name, receiver's email &amp; name, subject, and the
@@ -1913,7 +1915,7 @@ public abstract class Email
 
         try
         {
-            address = new InternetAddress(email);
+            address = new InternetAddress(new 
IDNEmailAddressConverter().toASCII(email));
 
             // check name input
             if (EmailUtils.isNotEmpty(name))

Added: 
commons/proper/email/trunk/src/main/java/org/apache/commons/mail/util/IDNEmailAddressConverter.java
URL: 
http://svn.apache.org/viewvc/commons/proper/email/trunk/src/main/java/org/apache/commons/mail/util/IDNEmailAddressConverter.java?rev=1728011&view=auto
==============================================================================
--- 
commons/proper/email/trunk/src/main/java/org/apache/commons/mail/util/IDNEmailAddressConverter.java
 (added)
+++ 
commons/proper/email/trunk/src/main/java/org/apache/commons/mail/util/IDNEmailAddressConverter.java
 Mon Feb  1 21:25:23 2016
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.mail.util;
+
+import javax.mail.internet.InternetAddress;
+import java.net.IDN;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Converts email addresses containing International Domain Names into an ASCII
+ * representation suitable for sending an email.
+ *
+ * @see <a 
href="https://docs.oracle.com/javase/tutorial/i18n/network/idn.html";>https://docs.oracle.com/javase/tutorial/i18n/network/idn.html</a>
+ * @see <a 
href="https://en.wikipedia.org/wiki/Punycode";>https://en.wikipedia.org/wiki/Punycode</a>
+ * @see <a 
href="https://tools.ietf.org/html/rfc5891";>https://tools.ietf.org/html/rfc5891</a>
+ * @see <a 
href="https://en.wikipedia.org/wiki/Punycode";>https://en.wikipedia.org/wiki/Punycode</a>
+ *
+ * @version $Id$
+ * @since 1.5
+ */
+public class IDNEmailAddressConverter {
+
+    /**
+     * Convert an email address to its ASCII representation using "Punycode".
+     */
+    public String toASCII(final String email)
+    {
+        final int idx = findAtSymbolIndex(email);
+
+        if (idx < 0)
+        {
+            return email;
+        }
+
+        return getLocalPart(email, idx) + "@" + 
IDN.toASCII(getDomainPart(email, idx));
+    }
+
+    /**
+     * Convert an "Punycode" email address to its Unicode representation.
+     */
+    public String toUnicode(final String email)
+    {
+        final int idx = findAtSymbolIndex(email);
+
+        if (idx < 0)
+        {
+            return email;
+        }
+
+        return getLocalPart(email, idx) + "@" + 
IDN.toUnicode(getDomainPart(email, idx));
+    }
+
+    /**
+     * Convert the address part of an InternetAddress to its Unicode 
representation.
+     */
+    public String toUnicode(final InternetAddress address)
+    {
+        return (address != null ? toUnicode(address.getAddress()) : null);
+    }
+
+    /**
+     * Convert the address part of a list of InternetAddress to its Unicode 
representation.
+     */
+    public Collection<String> toUnicode(Collection<InternetAddress> addresses)
+    {
+        if(addresses == null)
+        {
+            return null;
+        }
+
+        Collection<String> result = new ArrayList<String>();
+
+        for(InternetAddress address : addresses)
+        {
+            result.add(toUnicode(address));
+        }
+
+        return result;
+    }
+
+    private String getLocalPart(final String email, final int idx)
+    {
+
+        return email.substring(0, idx);
+    }
+
+    private String getDomainPart(final String email, final int idx)
+    {
+
+        return email.substring(idx + 1);
+    }
+
+    private int findAtSymbolIndex(final String value)
+    {
+        if (value == null)
+        {
+            return -1;
+        }
+
+        return value.indexOf('@');
+    }
+}

Modified: 
commons/proper/email/trunk/src/test/java/org/apache/commons/mail/EmailTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/email/trunk/src/test/java/org/apache/commons/mail/EmailTest.java?rev=1728011&r1=1728010&r2=1728011&view=diff
==============================================================================
--- 
commons/proper/email/trunk/src/test/java/org/apache/commons/mail/EmailTest.java 
(original)
+++ 
commons/proper/email/trunk/src/test/java/org/apache/commons/mail/EmailTest.java 
Mon Feb  1 21:25:23 2016
@@ -31,6 +31,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
+import javax.mail.Message;
 import javax.mail.Session;
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
@@ -1266,4 +1267,25 @@ public class EmailTest extends AbstractE
         assertEquals(bounceAddress, email.getBounceAddress());        
     }
 
+    @Test
+    public void testSupportForInternationalDomainNames() throws Exception
+    {
+        email.setHostName(strTestMailServer);
+        email.setSmtpPort(getMailServerPort());
+        email.setFrom("from@d\u00F6m\u00E4in.example");
+        email.addTo("to@d\u00F6m\u00E4in.example");
+        email.addCc("cc@d\u00F6m\u00E4in.example");
+        email.addBcc("bcc@d\u00F6m\u00E4in.example");
+        email.setSubject("test mail");
+        email.setSubject("testSupportForInternationalDomainNames");
+        email.setMsg("This is a test mail ... :-)");
+
+        email.buildMimeMessage();
+        final MimeMessage msg = email.getMimeMessage();
+
+        assertEquals("from@xn--dmin-moa0i.example", 
msg.getFrom()[0].toString());
+        assertEquals("to@xn--dmin-moa0i.example", 
msg.getRecipients(Message.RecipientType.TO)[0].toString());
+        assertEquals("cc@xn--dmin-moa0i.example", 
msg.getRecipients(Message.RecipientType.CC)[0].toString());
+        assertEquals("bcc@xn--dmin-moa0i.example", 
msg.getRecipients(Message.RecipientType.BCC)[0].toString());
+    }
 }

Added: 
commons/proper/email/trunk/src/test/java/org/apache/commons/mail/util/IDNEmailAddressConverterTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/email/trunk/src/test/java/org/apache/commons/mail/util/IDNEmailAddressConverterTest.java?rev=1728011&view=auto
==============================================================================
--- 
commons/proper/email/trunk/src/test/java/org/apache/commons/mail/util/IDNEmailAddressConverterTest.java
 (added)
+++ 
commons/proper/email/trunk/src/test/java/org/apache/commons/mail/util/IDNEmailAddressConverterTest.java
 Mon Feb  1 21:25:23 2016
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.mail.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.mail.internet.InternetAddress;
+
+import org.junit.Test;
+
+public class IDNEmailAddressConverterTest {
+
+    private static final String AUSTRIAN_IDN_EMAIL_ADDRESS = 
"noreply@d\u00F6m\u00E4in.example";
+    private static final String CZECH_IDN_EMAIL_ADDRESS = 
"noreply@\u010Desk\u00E1republika.icom.museum";
+    private static final String RUSSIAN_IDN_EMAIL_ADDRESS = 
"noreply@\u0440\u043E\u0441\u0441\u0438\u044F.\u0438\u043A\u043E\u043C.museum";
+
+    private static final String GERMAN_IDN_EMAIL_NAME = 
"noreply@d\u00F6m\u00E4in.example";
+
+    private static final String[] IDN_EMAIL_ADDRESSES = { 
AUSTRIAN_IDN_EMAIL_ADDRESS, CZECH_IDN_EMAIL_ADDRESS, RUSSIAN_IDN_EMAIL_ADDRESS 
};
+
+    private IDNEmailAddressConverter idnEmailConverter = new 
IDNEmailAddressConverter();
+
+    @Test
+    public void testConvertInvalidEmailAddressToAscii()
+    {
+        assertEquals(null, idnEmailConverter.toASCII(null));
+        assertEquals("", idnEmailConverter.toASCII(""));
+        assertEquals("@", idnEmailConverter.toASCII("@"));
+        assertEquals("@@", idnEmailConverter.toASCII("@@"));
+        assertEquals("foo", idnEmailConverter.toASCII("foo"));
+        assertEquals("foo@", idnEmailConverter.toASCII("foo@"));
+        assertEquals("@badhost.com", 
idnEmailConverter.toASCII("@badhost.com"));
+    }
+
+    @Test
+    public void testIDNEmailAddressToAsciiConversion()
+    {
+        assertEquals("noreply@xn--dmin-moa0i.example", 
idnEmailConverter.toASCII(AUSTRIAN_IDN_EMAIL_ADDRESS));
+        assertEquals("nore...@xn--h1alffa9f.xn--h1aegh.museum", 
idnEmailConverter.toASCII(RUSSIAN_IDN_EMAIL_ADDRESS));
+    }
+
+    @Test
+    public void testMultipleIDNEmailAddressToAsciiConversion()
+    {
+        assertEquals("noreply@xn--dmin-moa0i.example", 
idnEmailConverter.toASCII(idnEmailConverter.toASCII(AUSTRIAN_IDN_EMAIL_ADDRESS)));
+    }
+
+    @Test
+    public void testInternetAddressToAsciiConversion() throws Exception
+    {
+        InternetAddress address = new 
InternetAddress(idnEmailConverter.toASCII(AUSTRIAN_IDN_EMAIL_ADDRESS));
+        assertEquals(AUSTRIAN_IDN_EMAIL_ADDRESS, 
idnEmailConverter.toUnicode(address));
+
+        InternetAddress addressWithPersonalName = new 
InternetAddress(idnEmailConverter.toASCII(AUSTRIAN_IDN_EMAIL_ADDRESS), 
GERMAN_IDN_EMAIL_NAME);
+        assertEquals(AUSTRIAN_IDN_EMAIL_ADDRESS, 
idnEmailConverter.toUnicode(addressWithPersonalName));
+    }
+
+    @Test
+    public void testInternetAddressCollectionToAsciiConversion() throws 
Exception
+    {
+        Collection<InternetAddress> addresses = new 
ArrayList<InternetAddress>();
+        addresses.add(new 
InternetAddress(idnEmailConverter.toASCII(AUSTRIAN_IDN_EMAIL_ADDRESS)));
+
+        Collection<String> emails = idnEmailConverter.toUnicode(addresses);
+
+        assertEquals(1, emails.size());
+        assertEquals(AUSTRIAN_IDN_EMAIL_ADDRESS, emails.iterator().next());
+    }
+
+    @Test
+    public void testRoundTripConversionOfIDNEmailAddress()
+    {
+        for(String email : IDN_EMAIL_ADDRESSES)
+        {
+            assertEquals(email, 
idnEmailConverter.toUnicode(idnEmailConverter.toASCII(email)));
+        }
+    }
+
+    @Test
+    public void testNonIDNEmailAddressToAsciiConversion()
+    {
+        assertEquals("m...@home.com", 
idnEmailConverter.toASCII("m...@home.com"));
+    }
+}


Reply via email to