All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pentaho.di.trans.steps.mailvalidator.MailValidation Maven / Gradle / Ivy

The newest version!
/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2017 by Hitachi Vantara : http://www.pentaho.com
 *
 *******************************************************************************
 *
 * Licensed 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.pentaho.di.trans.steps.mailvalidator;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Hashtable;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

import org.apache.commons.validator.GenericValidator;
import org.pentaho.di.core.logging.LogChannelInterface;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.i18n.BaseMessages;

public class MailValidation {

  private static Class PKG = MailValidatorMeta.class; // for i18n purposes, needed by Translator2!!

  public static boolean isRegExValid( String emailAdress ) {
    return GenericValidator.isEmail( emailAdress );
  }

  /**
   * verify if there is a mail server registered to the domain name. and return the email servers count
   */
  public static int mailServersCount( String hostName ) throws NamingException {
    Hashtable env = new Hashtable();
    env.put( "java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory" );
    DirContext ictx = new InitialDirContext( env );
    Attributes attrs = ictx.getAttributes( hostName, new String[] { "MX" } );
    Attribute attr = attrs.get( "MX" );
    if ( attr == null ) {
      return ( 0 );
    }
    return ( attr.size() );
  }

  private static String className() {
    return BaseMessages.getString( PKG, "MailValidator.ClassName" );
  }

  private static int hear( BufferedReader in ) throws IOException {
    String line = null;
    int res = 0;

    while ( ( line = in.readLine() ) != null ) {
      String pfx = line.substring( 0, 3 );
      try {
        res = Integer.parseInt( pfx );
      } catch ( Exception ex ) {
        res = -1;
      }
      if ( line.charAt( 3 ) != '-' ) {
        break;
      }
    }

    return res;
  }

  private static void say( BufferedWriter wr, String text ) throws IOException {
    wr.write( text + "\r\n" );
    wr.flush();

    return;
  }

  private static ArrayList getMX( String hostName ) throws NamingException {
    // Perform a DNS lookup for MX records in the domain
    Hashtable env = new Hashtable();
    env.put( "java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory" );
    DirContext ictx = new InitialDirContext( env );
    Attributes attrs = ictx.getAttributes( hostName, new String[] { "MX" } );
    Attribute attr = attrs.get( "MX" );

    // if we don't have an MX record, try the machine itself
    if ( ( attr == null ) || ( attr.size() == 0 ) ) {
      attrs = ictx.getAttributes( hostName, new String[] { "A" } );
      attr = attrs.get( "A" );
      if ( attr == null ) {
        throw new NamingException( BaseMessages.getString( PKG, "MailValidator.NoMatchName", hostName ) );
      }
    }

    // Huzzah! we have machines to try. Return them as an array list
    // NOTE: We SHOULD take the preference into account to be absolutely
    // correct. This is left as an exercise for anyone who cares.
    ArrayList res = new ArrayList();
    NamingEnumeration en = attr.getAll();

    while ( en.hasMore() ) {
      String x = (String) en.next();
      String[] f = x.split( " " );
      if ( f[1].endsWith( "." ) ) {
        f[1] = f[1].substring( 0, ( f[1].length() - 1 ) );
      }
      res.add( f[1] );
    }
    return res;
  }

  /**
   * Validate an email address This code is from : http://www.rgagnon.com/javadetails/java-0452.html
   *
   * @param email
   *          address
   * @param sender
   *          email address
   * @param default SMTP Server
   * @param timeout
   *          for socket connection
   * @param deepCheck
   *          (if we want to perform a SMTP check
   * @return true or false
   */
  public static MailValidationResult isAddressValid( LogChannelInterface log, String address,
    String senderAddress, String defaultSMTPServer, int timeout, boolean deepCheck ) {

    MailValidationResult result = new MailValidationResult();

    if ( !isRegExValid( address ) ) {
      result.setErrorMessage( BaseMessages.getString( PKG, "MailValidator.MalformedAddress", address ) );
      return result;
    }

    // Find the separator for the domain name
    int pos = address.indexOf( '@' );

    // If the address does not contain an '@', it's not valid
    if ( pos == -1 ) {
      return result;
    }

    if ( !deepCheck ) {
      result.setValide( true );
      return result;
    }

    // Isolate the domain/machine name and get a list of mail exchangers
    String domain = address.substring( ++pos );

    // Maybe user want to switch to a default SMTP server?
    // In that case, we will ignore the domain
    // extracted from email address

    ArrayList mxList = new ArrayList();
    if ( Utils.isEmpty( defaultSMTPServer ) ) {
      try {
        mxList = getMX( domain );

        // Just because we can send mail to the domain, doesn't mean that the
        // address is valid, but if we can't, it's a sure sign that it isn't
        if ( mxList == null || mxList.size() == 0 ) {
          result.setErrorMessage( BaseMessages.getString( PKG, "MailValidator.NoMachinesInDomain", domain ) );
          return result;
        }
      } catch ( Exception ex ) {
        result.setErrorMessage( BaseMessages.getString( PKG, "MailValidator.ErrorGettingMachinesInDomain", ex
          .getMessage() ) );
        return result;
      }
    } else {
      mxList.add( defaultSMTPServer );
    }

    if ( log.isDebug() ) {
      log.logDebug( BaseMessages.getString( PKG, "MailValidator.ExchangersFound", "" + mxList.size() ) );
    }

    // Now, do the SMTP validation, try each mail exchanger until we get
    // a positive acceptance. It *MAY* be possible for one MX to allow
    // a message [store and forwarder for example] and another [like
    // the actual mail server] to reject it. This is why we REALLY ought
    // to take the preference into account.
    for ( int mx = 0; mx < mxList.size(); mx++ ) {
      boolean valid = false;
      BufferedReader rdr = null;
      BufferedWriter wtr = null;
      Socket skt = null;
      try {
        String exhanger = mxList.get( mx );
        if ( log.isDebug() ) {
          log.logDebug( className(), BaseMessages.getString( PKG, "MailValidator.TryingExchanger", exhanger ) );
        }

        int res;

        skt = new Socket( exhanger, 25 );
        // set timeout (milliseconds)
        if ( timeout > 0 ) {
          skt.setSoTimeout( timeout );
        }

        if ( log.isDebug() ) {
          log.logDebug( className(), BaseMessages.getString(
            PKG, "MailValidator.ConnectingTo", exhanger, "25", skt.isConnected() + "" ) );
        }

        rdr = new BufferedReader( new InputStreamReader( skt.getInputStream() ) );
        wtr = new BufferedWriter( new OutputStreamWriter( skt.getOutputStream() ) );

        res = hear( rdr );
        if ( res != 220 ) {
          throw new Exception( BaseMessages.getString( PKG, "MailValidator.InvalidHeader" ) );
        }

        // say HELLO it's me
        if ( log.isDebug() ) {
          log.logDebug( className(), BaseMessages.getString( PKG, "MailValidator.SayHello", domain ) );
        }
        say( wtr, "EHLO " + domain );
        res = hear( rdr );
        if ( res != 250 ) {
          throw new Exception( "Not ESMTP" );
        }
        if ( log.isDebug() ) {
          log.logDebug( className(), BaseMessages.getString( PKG, "MailValidator.ServerReplied", "" + res ) );
        }

        // validate the sender address
        if ( log.isDebug() ) {
          log.logDebug( className(), BaseMessages.getString( PKG, "MailValidator.CheckSender", senderAddress ) );
        }
        say( wtr, "MAIL FROM: <" + senderAddress + ">" );
        res = hear( rdr );
        if ( res != 250 ) {
          throw new Exception( BaseMessages.getString( PKG, "MailValidator.SenderRejected" ) );
        }
        if ( log.isDebug() ) {
          log.logDebug( className(), BaseMessages.getString( PKG, "MailValidator.SenderAccepted", "" + res ) );
        }

        // Validate receiver
        if ( log.isDebug() ) {
          log.logDebug( className(), BaseMessages.getString( PKG, "MailValidator.CheckReceiver", address ) );
        }
        say( wtr, "RCPT TO: <" + address + ">" );
        res = hear( rdr );

        // be polite
        say( wtr, "RSET" );
        hear( rdr );
        say( wtr, "QUIT" );
        hear( rdr );
        if ( res != 250 ) {
          throw new Exception( BaseMessages.getString( PKG, "MailValidator.AddressNotValid", address ) );
        }

        if ( log.isDebug() ) {
          log.logDebug( className(), BaseMessages.getString( PKG, "MailValidator.ReceiverAccepted", address, ""
            + res ) );
        }
        valid = true;

      } catch ( Exception ex ) {
        // Do nothing but try next host
        result.setValide( false );
        result.setErrorMessage( ex.getMessage() );
      } finally {
        if ( rdr != null ) {
          try {
            rdr.close();
          } catch ( Exception e ) {
            // ignore this
          }
        }
        if ( wtr != null ) {
          try {
            wtr.close();
          } catch ( Exception e ) {
            // ignore this
          }
        }
        if ( skt != null ) {
          try {
            skt.close();
          } catch ( Exception e ) {
            // ignore this
          }
        }

        if ( valid ) {
          result.setValide( true );
          result.setErrorMessage( null );
          if ( log.isDebug() ) {
            log.logDebug( className(), "=============================================" );
          }
          return result;
        }
      }
    }
    if ( log.isDebug() ) {
      log.logDebug( className(), "=============================================" );
    }

    return result;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy