/* * [CachedMailProber.java] * * Summary: A persistent cache of DomainStatuses. * * Copyright: (c) 2002-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2002-04-13 original */ package com.mindprod.bulk; import com.mindprod.common18.EIO; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.HashMap; import java.util.Iterator; import static com.mindprod.bulk.CustConfig.CUST_ABBREVIATION; import static com.mindprod.bulk.CustConfig.TREAT_AS_BAD_DOMAINS; import static com.mindprod.bulk.CustConfig.TREAT_AS_GOOD_DOMAINS; import static java.lang.System.*; /** * A persistent cache of DomainStatuses. *

* e.g. where a given domain has a working mailserver. * Has provision to cull deadwood. Uses serialisation. * The idea is to avoid the overhead of probing a mailserver for every email validation. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2002-04-13 original * @since 2002-04-13 */ public final class CachedMailProber { /** * name of the file where we cache status of various email domains. */ private static final String DOMAIN_CACHE_FILE_NAME = CUST_ABBREVIATION + "-domain-cache.ser"; /** * collection of previously probed Domains along with their statuses. */ private static HashMap domainCache; static { /* load up serialised domainCache from before */ fireup(); } /** * Called when class is shut down to save the domainCache in serialised form. */ private static void close() { flush(); domainCache = null; } /** * Called when class is loaded to reconstitute the serialised domainCache. Called automatically when class is * loaded. */ @SuppressWarnings( "unchecked" ) private static void fireup() { try { // O P E N ObjectInputStream ois = EIO.getObjectInputStream( new File( DOMAIN_CACHE_FILE_NAME ), 4 * 1024, false ); // R E A D domainCache = ( HashMap ) ois.readObject(); // C L O S E ois.close(); } catch ( Exception e ) { out.println( "Troubles restoring the " + DOMAIN_CACHE_FILE_NAME + " file. Not to worry, starting afresh." ); domainCache = new HashMap<>( 2053, 0.75f ); } /* seed the special exceptions. Might be already there, no problem */ for ( String treatAsGoodDomain : TREAT_AS_GOOD_DOMAINS ) { domainCache.put( treatAsGoodDomain, new DomainStatus( treatAsGoodDomain, true ) ); } for ( String treatAsBadDomain : TREAT_AS_BAD_DOMAINS ) { domainCache.put( treatAsBadDomain, new DomainStatus( treatAsBadDomain, false ) ); } } // end fireup /** * Test the mailserver status of a domain. * * @param domain name of domain, (will be automatically trimmed and converted internally to lower case), whose * status we are interested in e.g. mindprod.com or oberon.ark.com, not the mailserver name, not an * email address. * * @return true if that domain existed in DNS records at the last probe, and one of whose mailservers responded at * least one in recent probes. Reprobes as necessary. */ private static boolean isMailServerForDomainAlive( String domain ) { if ( domain == null ) { return false; } domain = domain.trim().toLowerCase(); DomainStatus d = domainCache.get( domain ); if ( d == null ) { /* not in domainCache yet, put it there. */ d = new DomainStatus( domain ); domainCache.put( domain, d ); } return d.isGood(); } /** * Tests if mailserver corresponding to that email is up and running. * * @param email email address you are proposing to send to. * * @return true if that the corresponding mailserver is working, or was working recently. */ @SuppressWarnings( { "ConstantConditions", "PointlessBooleanExpression" } ) static boolean isMailServerForEmailAlive( String email ) { if ( !CustConfig.VALIDATE_EMAIL_SERVERS ) { // If can't access mail servers directly, just assume all is ox. return true; } if ( email == null ) { return false; } email = email.trim().toLowerCase(); int lastAt = email.lastIndexOf( '@' ); if ( lastAt < 0 ) { return false; } String domain = email.substring( lastAt + 1 ); return isMailServerForDomainAlive( domain ); } /** * save the domainCache in serialised form. */ public static void flush() { try { // C U L L for ( Iterator iter = domainCache.values().iterator(); iter.hasNext(); ) { DomainStatus d = ( DomainStatus ) iter.next(); if ( d.shouldCull() ) { iter.remove();// avoid ConcurrentModificationException } } // end for // O P E N FileOutputStream fos = new FileOutputStream( DOMAIN_CACHE_FILE_NAME, false /* append */ ); ObjectOutputStream oos = new ObjectOutputStream( fos ); // W R I T E oos.writeObject( domainCache ); // C L O S E oos.close(); } catch ( IOException e ) { err.println(); e.printStackTrace( err ); err.println( "Troubles writing out the " + DOMAIN_CACHE_FILE_NAME + " file" ); err.println(); } } // end close /** * test driver * * @param args sample email addresses to test for working mailservers */ public static void main( String[] args ) { for ( String email : args ) { out.println( email + " " + isMailServerForEmailAlive( email ) ); } close(); } }