I have a requirement wherein an IP address can have multiple hostnames mapped to it. I tried looking into InetAddress.getAllByName("10.33.28.55") however I did not get the desired result, it returned just one entry. nslookup on the IP address returns all DNS entries. How do I retrieve all the hostnames associated with this IP address in Java?
Looking at the source code for InetAddress.getAllByName() you find that it doesn't actually do a DNS query if the provided String is textual representation of an IP address. It simply returns an array containing a single InetAdddress object containing the IP. They even put a handy comment right in the method:
// if host is an IP address, we won't do further lookup
(See: http://javasourcecode.org/html/open-source/jdk/jdk-6u23/java.net/InetAddress.java.html)
If only the JavaDoc was so clear. It states "If a literal IP address is supplied, only the validity of the address format is checked." ... I would argue that doesn't tell you that it isn't going to be looked up.
Thinking about it, however ... it makes sense in the context of InetAddress - the class encapsulates an IP address of which ... you only have one. It really needs getHostNames() and getAllCanonicalNames() (note the plurality) methods that would do what you are asking. I'm thinking of opening an issue / submitting a patch.
That said, it would appear currently there's no built in method of doing a RDNS query where multiple PTR records are supported. All the other lookup methods simply lop off the first record returned and that's what you get.
You're going to have to look into 3rd party DNS libraries for java (sorry, I don't have experience with using any of them).
Edit to add: I like figuring things out. I do not have an IP handy that has multiple PTR records to test this against, but it should do the trick.
import java.io.IOException;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
public class App
{
public static void main(String[] args) throws IOException, NamingException
{
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
InitialDirContext idc = new InitialDirContext(env);
String ipAddr = "74.125.225.196";
// Turn the IP into an in-addr.arpa name
// 196.225.125.74.in-addr.arpa.
String[] quads = ipAddr.split("\\.");
StringBuilder sb = new StringBuilder();
for (int i = quads.length - 1; i >= 0; i--)
{
sb.append(quads[i]).append(".");
}
sb.append("in-addr.arpa.");
ipAddr = sb.toString();
Attributes attrs = idc.getAttributes(ipAddr, new String[] {"PTR"});
Attribute attr = attrs.get("PTR");
if (attr != null)
{
for (int i = 0; i < attr.size(); i++)
{
System.out.println((String)attr.get(i));
}
}
}
}
Well, there is only one good way: call nslookup or dig or whatever from the Java process.
With Runtime.getRuntime().exec(..)
or better with ProcessBuilder...
This answer might be helpful: https://stackoverflow.com/a/24205035/8026752
Using the lookupAllHostAddr method of DNSNameService works for me, and returns all IP addresses by hostname. Maybe it will also help with finding all hostnames by IP address, but it seems this depends on DNS server configuration. In my case I even couldn't find all hostnames using nslookup, so I couldn't test it, so I'm not sure about this solution.
One suggestion is that lookupAllHostAddr is not static method, so you should use it like this:
InetAddress[] ipAddress = new DNSNameService().lookupAllHostAddr("hostname")
Also, from my perspective, this link could be interesting (it's also information from the same answer thread mentioned by me above, I just summarize it a bit):
https://docs.oracle.com/javase/8/docs/technotes/guides/net/properties.html
On the linked page you can find properties to disable lookups caching:
sun.net.inetaddr.ttl - you should add it to JVM start command line like this: -Dsun.net.inetaddr.ttl=0, 0 here means that hostname will be cached for 0 seconds
networkaddress.cache.ttl - you should add the needed value to the java.security file located at %JRE%\lib\security
A bit more info can be found here also:
http://www.rgagnon.com/javadetails/java-0445.html
Related
I am converting a nodejs code into Java8.
In node there are code as shown below
var ipToEndAt = ippp.prev("192.168.1.225");
result of ipToEndAt is "192.168.1.224"
I need to convert this line into a java code. I searched for SubnetUtils library, but couldn't find anything appropriate.
similar i also need to increment ip address by 1
can anyone suggest a library or a code snippet ? which ever would be best
Although it's not overly hard to do it yourself, there's an InetAddresses class in Guava that allows this kind of operations. And Guava is a very useful addition to your toolchest anyways.
InetAddress address = InetAddress.getByName("192.168.1.225");
address = InetAddresses.decrement(address);
See, that looks almost identical to the JS code.
In your comment you state that you are unable to use the decrement method, which indicates that you have a really old version of Guava.
https://github.com/google/guava/commit/d39130651d8a90f5ebe066de7f0b2311806e5152#diff-1207ec0a4b5d3f5e5c2236b7373eefc9
The project home page contains instructions on how to add the current version (25.1) to your project's dependencies.
This can be done with the IPAddress Java library, in a manner that is polymorphic between IPv4 and IPv6. Also, it is not limited to incrementing or decrementing by 1 as with Guava, you can use any long value and catch AddressValueException in the case of overflow. Disclaimer: I am the project manager of IPAddress.
Sample code:
IPAddress result = increment("192.168.1.225", -1);
System.out.println(result);
result = increment("::", 1);
System.out.println(result);
static IPAddress increment(String addrStr, long inc) throws AddressValueException {
return new IPAddressString(addrStr).getAddress().increment(inc);
}
Output:
192.168.1.224
::1
More elaborate sample code at the IPAddress wiki
Which of the following is the best and most portable way to get the hostname of the current computer in Java?
Runtime.getRuntime().exec("hostname")
vs
InetAddress.getLocalHost().getHostName()
Strictly speaking - you have no choice but calling either hostname(1) or - on Unix gethostname(2). This is the name of your computer. Any attempt to determine the hostname by an IP address like this
InetAddress.getLocalHost().getHostName()
is bound to fail in some circumstances:
The IP address might not resolve into any name. Bad DNS setup, bad system setup or bad provider setup may be the reason for this.
A name in DNS can have many aliases called CNAMEs. These can only be resolved in one direction properly: name to address. The reverse direction is ambiguous. Which one is the "official" name?
A host can have many different IP addresses - and each address can have many different names. Two common cases are: One ethernet port has several "logical" IP addresses or the computer has several ethernet ports. It is configurable whether they share an IP or have different IPs. This is called "multihomed".
One Name in DNS can resolve to several IP Addresses. And not all of those addresses must be located on the same computer! (Usecase: A simple form of load-balancing)
Let's not even start talking about dynamic IP addresses.
Also don't confuse the name of an IP-address with the name of the host (hostname). A metaphor might make it clearer:
There is a large city (server) called "London". Inside the city walls much business happens. The city has several gates (IP addresses). Each gate has a name ("North Gate", "River Gate", "Southampton Gate"...) but the name of the gate is not the name of the city. Also you cannot deduce the name of the city by using the name of a gate - "North Gate" would catch half of the bigger cities and not just one city. However - a stranger (IP packet) walks along the river and asks a local: "I have a strange address: 'Rivergate, second left, third house'. Can you help me?" The local says: "Of course, you are on the right road, simply go ahead and you will arrive at your destination within half an hour."
This illustrates it pretty much I think.
The good news is: The real hostname is usually not necessary. In most cases any name which resolves into an IP address on this host will do. (The stranger might enter the city by Northgate, but helpful locals translate the "2nd left" part.)
In the remaining corner cases you must use the definitive source of this configuration setting - which is the C function gethostname(2). That function is also called by the program hostname.
InetAddress.getLocalHost().getHostName() is the more portable way.
exec("hostname") actually calls out to the operating system to execute the hostname command.
Here are a couple other related answers on SO:
Java current machine name and logged in user?
Get DNS name of local machine as seen by a remote machine
EDIT: You should take a look at A.H.'s answer or Arnout Engelen's answer for details on why this might not work as expected, depending on your situation. As an answer for this person who specifically requested portable, I still think getHostName() is fine, but they bring up some good points that should be considered.
As others have noted, getting the hostname based on DNS resolution is unreliable.
Since this question is unfortunately still relevant in 2018, I'd like to share with you my network-independent solution, with some test runs on different systems.
The following code tries to do the following:
On Windows
Read the COMPUTERNAME environment variable through System.getenv().
Execute hostname.exe and read the response
On Linux
Read the HOSTNAME environment variable through System.getenv()
Execute hostname and read the response
Read /etc/hostname (to do this I'm executing cat since the snippet already contains code to execute and read. Simply reading the file would be better, though).
The code:
public static void main(String[] args) throws IOException {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
System.out.println("Windows computer name through env:\"" + System.getenv("COMPUTERNAME") + "\"");
System.out.println("Windows computer name through exec:\"" + execReadToString("hostname") + "\"");
} else if (os.contains("nix") || os.contains("nux") || os.contains("mac os x")) {
System.out.println("Unix-like computer name through env:\"" + System.getenv("HOSTNAME") + "\"");
System.out.println("Unix-like computer name through exec:\"" + execReadToString("hostname") + "\"");
System.out.println("Unix-like computer name through /etc/hostname:\"" + execReadToString("cat /etc/hostname") + "\"");
}
}
public static String execReadToString(String execCommand) throws IOException {
try (Scanner s = new Scanner(Runtime.getRuntime().exec(execCommand).getInputStream()).useDelimiter("\\A")) {
return s.hasNext() ? s.next() : "";
}
}
Results for different operating systems:
macOS 10.13.2
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:""
OpenSuse 13.1
Unix-like computer name through env:"machinename"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:""
Ubuntu 14.04 LTS
This one is kinda strange since echo $HOSTNAME returns the correct hostname, but System.getenv("HOSTNAME") does not:
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:"machinename
"
EDIT: According to legolas108, System.getenv("HOSTNAME") works on Ubuntu 14.04 if you run export HOSTNAME before executing the Java code.
Windows 7
Windows computer name through env:"MACHINENAME"
Windows computer name through exec:"machinename
"
Windows 10
Windows computer name through env:"MACHINENAME"
Windows computer name through exec:"machinename
"
The machine names have been replaced but I kept the capitalization and structure. Note the extra newline when executing hostname, you might have to take it into account in some cases.
InetAddress.getLocalHost().getHostName() is better (as explained by Nick), but still not very good
One host can be known under many different hostnames. Usually you'll be looking for the hostname your host has in a specific context.
For example, in a web application, you might be looking for the hostname used by whoever issued the request you're currently handling. How to best find that one depends on which framework you're using for your web application.
In some kind of other internet-facing service, you'll want the hostname your service is available through from the 'outside'. Due to proxies, firewalls etc this might not even be a hostname on the machine your service is installed on - you might try to come up with a reasonable default, but you should definitely make this configurable for whoever installs this.
Although this topic has already been answered there's more to say.
First of all: Clearly we need some definitions here. The InetAddress.getLocalHost().getHostName() gives you the name of the host as seen from a network perspective. The problems with this approach are well documented in the other answers: it often requires a DNS lookup, it's ambiguous if the host has multiple network interfaces and it just plain fails sometimes (see below).
But on any OS there's another name as well. A name of the host that gets defined very early in the boot process, long before the network is initialized. Windows refers to this as computername, Linux calls it kernel hostname and Solaris uses the word nodename. I like best the word computername, so I'll use that word from now on.
Finding the computername
On Linux/Unix the computername is what you get from the C function gethostname(), or hostname command from shell or HOSTNAME environment variable in Bash-like shells.
On Windows the computername is what you get from environment variable COMPUTERNAME or Win32 GetComputerName function.
Java has no way of obtaining what I've defined as 'computername'. Sure, there are workarounds as described in other answers, like for Windows calling System.getenv("COMPUTERNAME"), but on Unix/Linux there's no good workaround without resorting to JNI/JNA or Runtime.exec(). If you don't mind a JNI/JNA solution then there's gethostname4j which is dead simple and very easy to use.
Let's move on with two examples, one from Linux and one from Solaris, which demonstrate how you can easily get into a situation where you cannot obtain the computername using standard Java methods.
Linux example
On a newly created system, where the host during installation has been named as 'chicago', we now change the so-called kernel hostname:
$ hostnamectl --static set-hostname dallas
Now the kernel hostname is 'dallas', as evident from the hostname command:
$ hostname
dallas
But we still have
$ cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 chicago
There's no misconfiguration in this. It just means the host's networked name (or rather the name of the loopback interface) is different from the host's computername.
Now, try executing InetAddress.getLocalHost().getHostName() and it will throw java.net.UnknownHostException. You are basically stuck. There's no way to retrieve neither the value 'dallas' nor the value 'chicago'.
Solaris example
The example below is based on Solaris 11.3.
The host has deliberately been configured so that the loopback name <> nodename.
In other words we have:
$ svccfg -s system/identity:node listprop config
...
...
config/loopback astring chicago
config/nodename astring dallas
and the contents of /etc/hosts :
:1 chicago localhost
127.0.0.1 chicago localhost loghost
and the result of the hostname command would be:
$ hostname
dallas
Just like in the Linux example a call to InetAddress.getLocalHost().getHostName() will fail with
java.net.UnknownHostException: dallas: dallas: node name or service name not known
Just like the Linux example you are now stuck. There's no way to retrieve neither the value 'dallas' nor the value 'chicago'.
When will you really struggle with this?
Very often you'll find that InetAddress.getLocalHost().getHostName() will indeed return a value which is equal to the computername. So there's no problem (except for the added overhead of name resolution).
The problem arises typically within PaaS environments where there's a difference between computername and the name of the loopback interface. For example people report problems in Amazon EC2.
Bug/RFE reports
A bit of searching reveals this RFE report : link1, link2. However, judging from the comments on that report the issue seems to have been largely misunderstood by the JDK team, so it is unlikely it will be addressed.
I like the comparison in the RFE to other programming languages.
Just one-liner ... cross platform (Windows-Linux-Unix-Mac(Unix)) [Always works, No DNS required]:
String hostname = new BufferedReader(
new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream()))
.readLine();
You're done !!
Environment variables may also provide a useful means -- COMPUTERNAME on Windows, HOSTNAME on most modern Unix/Linux shells.
See: https://stackoverflow.com/a/17956000/768795
I'm using these as "supplementary" methods to InetAddress.getLocalHost().getHostName(), since as several people point out, that function doesn't work in all environments.
Runtime.getRuntime().exec("hostname") is another possible supplement. At this stage, I haven't used it.
import java.net.InetAddress;
import java.net.UnknownHostException;
// try InetAddress.LocalHost first;
// NOTE -- InetAddress.getLocalHost().getHostName() will not work in certain environments.
try {
String result = InetAddress.getLocalHost().getHostName();
if (StringUtils.isNotEmpty( result))
return result;
} catch (UnknownHostException e) {
// failed; try alternate means.
}
// try environment properties.
//
String host = System.getenv("COMPUTERNAME");
if (host != null)
return host;
host = System.getenv("HOSTNAME");
if (host != null)
return host;
// undetermined.
return null;
The most portable way to get the hostname of the current computer in Java is as follows:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class getHostName {
public static void main(String[] args) throws UnknownHostException {
InetAddress iAddress = InetAddress.getLocalHost();
String hostName = iAddress.getHostName();
//To get the Canonical host name
String canonicalHostName = iAddress.getCanonicalHostName();
System.out.println("HostName:" + hostName);
System.out.println("Canonical Host Name:" + canonicalHostName);
}
}
If you're not against using an external dependency from maven central, I wrote gethostname4j to solve this problem for myself. It just uses JNA to call libc's gethostname function (or gets the ComputerName on Windows) and returns it to you as a string.
https://github.com/mattsheppard/gethostname4j
hostName == null;
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
{
while (interfaces.hasMoreElements()) {
NetworkInterface nic = interfaces.nextElement();
Enumeration<InetAddress> addresses = nic.getInetAddresses();
while (hostName == null && addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (!address.isLoopbackAddress()) {
hostName = address.getHostName();
}
}
}
}
Building off of Dan Ortega's answer, I created a generic executeCommand(String) method that takes a command as a paramater.
import java.io.*;
public class SystemUtil {
public static void main(String[] args) throws IOException {
System.out.println(retrieveHostName());
}
public static String retrieveHostName() throws IOException {
return executeCommand("hostname");
}
private static String executeCommand(String command) throws IOException {
return new BufferedReader(
new InputStreamReader(Runtime.getRuntime().exec(command).getInputStream()))
.readLine();
}
}
InetAddress.getLocalHost().getHostName() is the best way out of the two as this is the best abstraction at the developer level.
MIME message senders appear in formats such as:
"John Doe" <johndoe#gmail.com>
<johndoe#gmail.com>
I'm trying to figure out how to extract the string "johndoe#gmail.com" in the above examples, although I will also need the "johndoe" and "gmail.com" parts (per RFC I'm pretty sure splitting on # is all that's needed from here). Obviously regex-ing up my own parser is one (not great) option.
It seemed this may be possible using javax.mail.internet.MimeMessage. All of the constructors require a Folder which I do not have (well, I sort of do, it exists in the IMAP layer), e.g.
MimeMessage(Folder folder, InputStream is, int msgnum)
Which makes me feel I'm using this class wrong. Nonetheless, if I parse this way I do get access to the getFrom() method which returns an array of Address, which itself doesn't offer methods of use to me.
Using mime4j it's easy to get this far:
case T_FIELD: // field means header
if(token.getName() == "from") {
// get raw string as above - unparsed
So using mime4j or using java, javax etc. utilities it should be possible to extract the "a#b.com" part of the address from there, but I haven't found a class within javax or mime4j that is responsible for this yet.
I think you need InternetAddress class from javax.mail:
http://docs.oracle.com/javaee/6/api/javax/mail/internet/InternetAddress.html#getAddress()
Minimum working example:
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
public class JavaMailExample {
public static void main(String[] args) throws AddressException {
String fullemail = "\"John Doe\" <johndoe#gmail.com>";
InternetAddress addr = new InternetAddress(fullemail);
System.out.println(addr.getPersonal()); // John Doe
System.out.println(addr.getAddress()); // johndoe#gmail.com
}
}
For my project I wanted to get a list of all available broadcast addresses so I could broadcast a request and my other application located on other computer in the unspecified network would respond and to get the list I (now using little modified version with contribution of Mike) came up with this:
private ArrayList<InetAddress> getBroadcastAddresses() {
ArrayList<InetAddress> listOfBroadcasts = new ArrayList();
Enumeration list;
try {
list = NetworkInterface.getNetworkInterfaces();
while(list.hasMoreElements()) {
NetworkInterface iface = (NetworkInterface) list.nextElement();
if(iface == null) continue;
if(!iface.isLoopback() && iface.isUp()) {
System.out.println("Found non-loopback, up interface:" + iface);
Iterator it = iface.getInterfaceAddresses().iterator();
while (it.hasNext()) {
InterfaceAddress address = (InterfaceAddress) it.next();
System.out.println("Found address: " + address);
if(address == null) continue;
InetAddress broadcast = address.getBroadcast();
if(broadcast != null) listOfBroadcasts.add(broadcast);
}
}
}
} catch (SocketException ex) {
return new ArrayList<InetAddress>();
}
return site;
}
It works quite well for reqular LAN however when it comes to the WiFi LAN it just skips the second while loop after one step because of having address equals null even though when I used System.out.println(interfaceItem) just to view what interfaces are being gone through it wrote wireless LAN's name and my IP corresponding to the network.
EDIT 1:
This is the output where 172.16.1.104 is my IP in the wireless network. The problem appears ONLY on my notebook with Wifi. The output is from my notebook where I mostly use wireless and sometimes I use UTP to connect with my friend. There is also one network interface of VirtualBox on my notebook.
Could you tell me what's wrong with it? Thank you!
Note: So it turns out that this might be problem for my notebook in particular and the code works for everybody else in general, I love this kind of problem :-) Seems like a dead end to me but thank for help anyway :-)Still love you! ;-)
I think you'll need to iterate across all the addresses, and additionally check if the broadcast address is null as well.
Consider that you might have addresses that you aren't expecting assigned to the interface as well. On my Linux system, with your code the first address I see is an IPv6 address, with a null broadcast (since there is no such thing as an IPv6 broadcast - though you can use multicast to achieve the same effect).
You need to completely remove the 1st way section of code. When you continue; there you'll go to the next interface instead of considering the possibility that there are two addresses.
The other reason why you always want to iterate all the addresses that can have broadcasts is because you need to consider that you might have addresses on two networks assigned to an interface. For example, you might have an interface with both 192.168.0.1/24 and 172.16.0.1/24 assigned.
Also, consider using a Set to store the broadcast addresses to protect against the case where you might have two addresses on the same subnet assigned.
Finally, since using broadcast addresses will restrict you to talking only to hosts that have an IP address in the same subnet, you might miss hosts that are not configured properly with the same subnet/netmask. So you might want to consider using multicast for this; you could use the IPv4 (or IPv6) all nodes multicast addresses to reach all hosts on the subnet, regardless of the configured address. (224.0.0.1 and FF01::1, respectively)
Edit: You also have a bug on the 2nd way, related to your use of the iterator. Since you're getting a new .iterator() each time around the for loop, you're lucky there isn't an infinite loop here. I changed your code to this, and it works for me:
$ cat Broadcasts.java
import java.net.*;
import java.util.*;
public class Broadcasts
{
public static void main(String[] args)
{
HashSet<InetAddress> listOfBroadcasts = new HashSet<InetAddress>();
Enumeration list;
try {
list = NetworkInterface.getNetworkInterfaces();
while(list.hasMoreElements()) {
NetworkInterface iface = (NetworkInterface) list.nextElement();
if(iface == null) continue;
if(!iface.isLoopback() && iface.isUp()) {
//System.out.println("Found non-loopback, up interface:" + iface);
Iterator it = iface.getInterfaceAddresses().iterator();
while (it.hasNext()) {
InterfaceAddress address = (InterfaceAddress) it.next();
//System.out.println("Found address: " + address);
if(address == null) continue;
InetAddress broadcast = address.getBroadcast();
if(broadcast != null)
{
System.out.println("Found broadcast: " + broadcast);
listOfBroadcasts.add(broadcast);
}
}
}
}
} catch (SocketException ex) {
System.err.println("Error while getting network interfaces");
ex.printStackTrace();
}
// return listOfBroadcasts;
}
}
Another problem you may run into is the try/catch around basically the entire function, which would cause this code to stop if it hit something unexpected. It would be better to surround possible failure points with a try/catch and do something sane (like skip the interface or address), but I didn't look at which methods can throw exceptions.
Edit 2: I misread your code; your iterator was fine. ;-) The problem (which I pointed out earlier) was that your 1st way is short-circuiting your 2nd way; since it hits the continue; statement, if the first address is null you don't even try to loop through them all.
In any case, run with those println statements and post the results if you're still having trouble.
Edit 3: OK, I give up. ;-) Based on the output you posted, it looks like you are running into a bug in the NetworkInterface class.
I don't know if it would help to turn off the preferIPv4Stack option, but you should test that. I searched around a little bit for bug reports that describe this behavior and could not find any.
Since you're on Linux, you could always take the fallback approach of shelling out and calling something like:
/sbin/ip addr | perl -ne 'print "$1\n" if $_ =~ /inet.* brd ([0-9\.]*)/'
... which should return you a list of broadcast addresses.
Edit 4: I just noticed in the JavaDoc for NetworkInterface there is a getSubInterfaces() call. Maybe you need to call this in order to make sure you get all the addresses? (it might help to post the output of /sbin/ip addr and /sbin/ifconfig)
Edit 5: Regarding the just-added bounty. (This question is over a year old!) Could someone please run the code in my answer above (edited to make it easy to copy/paste/run) and tell me if it works? If it doesn't, please edit the question and note the exact errors/problems.
Is there any way to verify in Java code that an e-mail address is valid. By valid, I don't just mean that it's in the correct format (someone#domain.subdomain), but that's it's a real active e-mail address.
I'm almost certain that there's no 100% reliable way to do this, because such a technique would be the stuff of spammer's dreams. But perhaps there's some technique that gives some useful indication about whether an address is 'real' or not.
Here is what I have around. To check that the address is a valid format, here is a regex that verifies that it's nearly rfc2822 (it doesn't catch some weird corner cases). I found it on the 'net last year.
private static final Pattern rfc2822 = Pattern.compile(
"^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$"
);
if (!rfc2822.matcher(email).matches()) {
throw new Exception("Invalid address");
}
That will take care of simple syntax (for the most part). The other check I know of will let you check if the domain has an MX record. It looks like this:
Hashtable<String, String> env = new Hashtable<String, String>();
env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
DirContext ictx = new InitialDirContext(env);
Attributes attrs = ictx.getAttributes(domainName, new String[] {"MX"});
Attribute attr = attrs.get("MX");
if (attr == null)
// No MX record
else
// If attr.size() > 0, there is an MX record
This, I also found on the 'net. It came from this link.
If these both pass, you have a good chance at having a valid address. As for if the address it's self (not just the domain), it's not full, etc... you really can't check that.
Note that the second check is time intensive. It can take anywhere from milliseconds to >30 seconds (if the DNS does not respond and times out). It's not something to try and run real-time for large numbers of people.
Hope this helps.
EDIT
I'd like to point out that, at least instead of the regex, there are better ways to check basic validity. Don and Michael point out that Apache Commons has something, and I recently found out you can use .validate() on InternetAddress to have Java check that the address is really RFC-8222, which is certainly more accurate than my regex.
You cannot really verify that an email exists, see my answer to a very similar question here: Email SMTP validator
Without sending an email, it could be hard to get 100%, but if you do a DNS lookup on the host that should at least tell you that it is a viable destination system.
Apache commons provides an email validator class too, which you can use. Simply pass your email address as an argument to isValid method.
Do a DNS lookup on the hostname to see if that exists. You could theoretically also initiate a connection to the mailserver and see if it tells you whether the recipient exists, but I think many servers pretend they know an address, then reject the email anyway.
The only way you can be certain is by actually sending a mail and have it read.
Let your registration process have a step that requires responding to information found only in the email. This is what others do.
I'm not 100% sure, but isn't it possible to send an RCPT SMTP command to a mail server to determine if the recipient is valid? It would be even more expensive than the suggestion above to check for a valid MX host, but it would also be the most accurate.
If you're using GWT, you can't use InternetAddress, and the pattern supplied by MBCook is pretty scary.
Here is a less scary regex (might not be as accurate):
public static boolean isValidEmail(String emailAddress) {
return emailAddress.contains(" ") == false && emailAddress.matches(".+#.+\\.[a-z]+");
}
public static boolean isValidEmail(String emailAddress) {
return emailAddress.contains(" ") == false && emailAddress.matches(".+#.+\\.[a-z]+");
}