Cómo enviar correos desde Android con Apache Commons


Trabajando con Android, muchos buscamos  enviar mensajes de correo electrónico usando un servidor SMTP, utilizando autenticación y cifrado, dentro de  de la propia aplicación android de forma que sea completamente transparente para el usuario.

Por desgracia javax.mail en Android no es una buena opción, ya que depende de las clases awt (problemas por la herencia) y no siempre funciona:no en vano ,de hecho algunas personas han tratado de adaptar la librería dado  que no ser requiere todo el paquete awt , pero lamentablemente han tenido poco éxito con eso; !y eso sin mencionar a quienes que refactorizando javax.mail para Android  (que lleva muchos  años, sin ningún mantenimiento)!.

Apache Commons es un conjunto de proyectos de Apache Software Foundation, que originalmente formaron parte de Jakarta Project. El propósito de estos proyectos consiste en proveer componentes de software Java reutilizables, en código abierto. Según su grado de madurez y actividad, los proyectos se agrupan en las categorías: proper, sandbox o dormant.

Otra opción mas pragmática pues  es usar Apache Commons ,puesto que la comunidad ha añadido un SMTPSClient y un AuthenticatingSMTPClient para el cliente SMTP original ,el cual con la  aplicación de un pequeño parche  para SSL y autenticación, se puede incrustar esta biblioteca en su aplicación para Android sin necesitar dependencias transitivas para enviar correo mediante la autenticación sobre una capa segura.

Autenticación SMTP y STARTTLS

STARTTLS es una extensión a los protocolos de comunicación de texto plano, que ofrece una forma de mejorar desde una conexión de texto plano a una conexión cifrada (TLS o SSL) en lugar de utilizar un puerto diferente para la comunicación cifrada.

El puerto utilizado para  envíos de correos es generalmente 25 o el puerto 587 alternativo por lo que lo que se trata es de conectar al servidor SMTP en una conexión simple, se piden los comandos disponibles, y si se soporta STARTTLS,se  usa ,y el resto de la comunicación está cifrado.

Ahora tomemos el ejemplo de gmail, ya que el servidor es  smtp.gmail.com , como soporta autenticación y STARTTLS  podemos enviar fácilmente correos si importamos la libreria Apache Commons

 

Un ejemplo de código funcional que podemos probar desde Android Studio es el siguiente:

com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.appindexing.Thing;
import com.google.android.gms.common.api.GoogleApiClient;
import org.apache.commons.net.smtp.AuthenticatingSMTPClient;

import org.apache.commons.net.smtp.SMTPClient;

import org.apache.commons.net.smtp.SMTPReply;

import org.apache.commons.net.smtp.SimpleSMTPHeader;  

  public void sendEmail()

{ String hostname = «smtp.gmail.com»;

int port = 587; String password = «xxxxxxxxx»;

// aqui necesitamos la pwd de al cuenta de gmail

String login = «[email protected]»;

//aqui necesitamos la cuenta de gmail desde //la que enviaremos los email desde la app

String from = login;

//aqui ponemos el nombre del correo de envío

// es el enviante

String subject = «subject«;

//asunto del correo

String text = «message»;

//texto del correo try

{ AuthenticatingSMTPClientclient = new AuthenticatingSMTPClient();

String to = «[email protected]»;

//destino del correo

// optionally set a timeout to have a faster

//feedback on errors client.setDefaultTimeout(10 * 1000);

// you connect to the SMTP server client.connect(hostname, port);

// you say ehlo  and you specify the host you are connecting from, //could be anything client.ehlo(«localhost»);

// if your host accepts STARTTLS, we’re good everything will be encrypted,

// otherwise we’re done here

if (client.execTLS())

{ client.auth(AuthenticatingSMTPClient.AUTH_METHOD.LOGIN, login, password);

checkReply(client); client.setSender(from);

checkReply(client);

client.addRecipient(to);

checkReply(client);

Writer writer = client.sendMessageData();

if (writer != null)

{ SimpleSMTPHeader header = new SimpleSMTPHeader(from, to, subject); writer.write(header.toString()); writer.write(text); writer.close();

if (!client.completePendingCommand())

{

// failure

throw new Exception(«Fallo al  enviar email » + client.getReply() + _ client.getReplyString()); } }

else

{ throw new Exception(«Fallo al enviar email » + client.getReply() + _ client.getReplyString()); } }

else

{ throw new Exception(«STARTTLS no fue aceptado » + client.getReply() +_ client.getReplyString());

} }

catch (Exception e) {

// some other problem

Toast.makeText(MainActivity.this, «Problema enviado email.», _ Toast.LENGTH_SHORT).show(); } }

 

private static void checkReply(SMTPClient sc) throws Exception

{ if (SMTPReply.isNegativeTransient(sc.getReplyCode()))

{ throw new Exception(«Transient SMTP error » + sc.getReply() + sc.getReplyString()); }

else if (SMTPReply.isNegativePermanent(sc.getReplyCode()))

{ throw new Exception(«Permanent SMTP error » + sc.getReply() + sc.getReplyString()); } }

//* * ATTENTION: This was auto-generated to implement the App Indexing API. * // See https://g.co/AppIndexing/AndroidStudio for more information. */

public Action getIndexApiAction()

{ Thing object = new Thing.Builder() .setName(«Main Page»)

// TODO: Define a title for the content shown.

// TODO: Make sure this auto-generated URL is correct.

.setUrl(Uri.parse(«http://[ENTER-YOUR-URL-HERE]»)) .build();

return new Action.Builder(Action.TYPE_VIEW) .setObject(object) ._ setActionStatus(Action.STATUS_TYPE_COMPLETED) .build(); }

 

@Override public void onStart()

{ super.onStart();

// ATTENTION: This was auto-generated to implement the App Indexing API.

// See https://g.co/AppIndexing/AndroidStudio for more information. client2.connect(); AppIndex.AppIndexApi.start(client2, getIndexApiAction()); }

@Override public void onStop()

{ super.onStop();

// ATTENTION: This was auto-generated to implement the App Indexing API

. // See https://g.co/AppIndexing/AndroidStudio for more information. AppIndex.AppIndexApi.end(client2,

getIndexApiAction());

client2.disconnect(); }

No hay mucho que añadir aquí, por supuesto, la manipulación de excepciones podría ser optimizado si utiliza sus propias clases de excepción y por ejemplo tanto el login como el pwd de gmail  pueden ser capturados en los ajustes de la aplicación para personalizarlo a voulntas.

Autenticación SMTP y SSL con Commons Net

Algunos servidores SMTP están configurados para aceptar sólo SSL  por lo  hay que asegurar la comunicación antes de emitir cualquier comando al servidor siendo generalmente el puerto usado el 465.

Por ejemplo  LaPoste.net oferece cuentas gratuitas de correo electrónico ofrecidas por la publicación francesa, asi que enviar correos desde  ahi seria similar a esto:

 public void sendEmail() throws Exception {  
    String hostname = "smtp.laposte.net";
    int port = 465;
    String password = "password";
    String login = "firstname.lastname";
    String from = login + "@laposte.net";
    String subject = "subject" ;
    String text = "message";
    // this is the important part : you tell your client to connect using 
    //SSL right away
   AuthenticatingSMTPClient client = new AuthenticatingSMTPClient("TLS",true);
    try {
      String to = "[email protected]";
      // optionally set a timeout to have a faster feedback on errors
      client.setDefaultTimeout(10 * 1000);
      client.connect(hostname, port);
      client.ehlo("localhost");
      client.auth(AuthenticatingSMTPClient.AUTH_METHOD.LOGIN, login, password);
      checkReply(client);
     client.setSender(from);
     checkReply(client);
      client.addRecipient(to);
      checkReply(client);
      Writer writer = client.sendMessageData();

      if (writer != null) {
        SimpleSMTPHeader header = new SimpleSMTPHeader(from, to, subject);
        writer.write(header.toString());
        writer.write(text);
        writer.close();
        if(!client.completePendingCommand()) {// failure
          throw new Exception("Failure to send the email "+ client.getReply() +_
 client.getReplyString());
        }
      } else  
{
        throw new Exception("Failure to send the email "+ client.getReply() + _
client.getReplyString());
      }

    } catch (Exception e) {
        throw e;
    } finally {
        client.logout();
        client.disconnect();
    }
  }

No repitimos el método checkReply () aquí, ya que es el mismo para ambos fragmentos de código

Usted habrá notado que el uso de SSL de inmediato significa que usted no tiene que buscar la respuesta execTls () (de hecho no funcionará si lo hace).

Dependencias

Eso es todo; Si desea hacer que estos ejemplos funcionen en su entorno, debe descargar la liberia  apache commons net 3.3 jar    y agregar el jar apache commons net 3.3 a su proyecto

 

 

coomons

Driver Lexmark x4850 para windows 10


Microsoft anunció en junio de 2015. el lanzamiento de su último sistema operativo, Windows 10, con el que pretendía alcanzar a sus mil millones de usuarios hasta el 2017.

Los analistas se mostraron favorables: era más rápido, funcional y simple que su versión anterior, la cual usaba Internet Explorer (en lugar de Edge) .

Entre sus muchas novedades destacaba el añorado regreso  del botón de inicio  y  sobre todo  el estreno del  asistente Cortana Cortana , el cual  permite activar recordatorios, identificar una canción o proporcionarte la información básica diaria: la situación del sistema de transportes o los resultados de sus equipos favoritos, por ejemplo.

En su primer mes, se registraron cerca de 75 millones de instalaciones a través de su actualización gratuita,pero pronto comenzaron a llover las críticas entre las qeu destaca la incompatibilidad manifiesta del hardware que  funcionaba perfectamente en sistemas operativos anteriores a windows 10, por ejemplo  muchas de las impresoras «antiguas».

Como ejemplo de esta incompatibilidad veamos la impresora multifunción  de inyección Lexmark X4850, la cual era  WIFI ofreciendo la comodidad de la tecnología inalámbrica combinada con eficiencia impresión a 2 caras. Este Uno Todo-en-uno escanea con facilidad, copia e imprime  rápido – hasta 30 ppm en negro y 27 ppm en color,pudiendo   imprimir en modo borrador y excluye tiempo de alimentación de la primera página y !hasta incluye un monitor tft en color para gestionar el interfaz!.

lexmark

Toda aquella persona que tuviese esta impresora se habrá dado cuenta de que si ha actualizado su ordenador a windows 10 , con una probabilidad altísima  se habra ddo cuenta no es reconocida  tanto por wifi como por usb.

Para terminar ademas, por si aun tiene dudas en el sitio oficial de lexmark   tampoco dan opcion de ofrecer un driver para windows 10

lex1

 

Ante un problema así  cuando la compañía no ofrezca controladores para dicha impresora para windows 10 ( y desconfíe de otras empresas que ofrecen driver genéricos prometiendo la panacea) ,podemos intentar mediante todavía instalar  el necesario driver  para windows 10

En primer lugar si la impresora es wifi y en su ordenador ya solo incluye puertos usb 3.0 , si es la impresora antigua ( con la lexmark X4850)  intente usarlo por wifi ya que muchas impresoras como esta no reconoce los puertos 3.0. Obviamente para usar la conexión por  wifi l,esta debe tenerla configurada en su impresora , labor que puede hacer con el sw incluido usando un ordenador mas antiguo ( o manteniendo la configuración que tuviese)

Una vez configurada la conexión wifi de la impresora , lo siguiente es imprimir la configuración de red  la impresora pues  ahí veremos la dirección Ip de acceso  a esta,lo siguiente es intentar conectarse a la impresora usando ese puerto , para lo cual iremos a Configuración–>Dispositivos-> Agregar una impresora o scanner

 

Pulsar  en el link «La impresora que deseo no esta en la lista»   y usar la opción tercera»agregar una impresora por medio de una dirección TCP/IP o un nombre de host»

 

agregar

 

 

Ahora es cuando tenemos que escribir la Ip de la impresora que obtuvimos  desde la propia impresora (en el ejemplo 192.168.1.54)

 

ip

Enseguida intenta acceder a la ip especificada:

detectadno

 

 

Si la ip es correcta, al rato pedirá instalar el controlador , el cual habrá que introducir manualmente:

 

controlador

En nuestro caso la impresora todo en uno lexmark  X4850 no consta en la lista de impresoras que aparece , así lo que se aconseja es pulsar sobre Windows Update para que windows  intente cargar todos los drives posibles.

Tras un rato mas o menos largo (varios minutos ) deberían aparecer en la lista otras lista de  impresoras de lexmark(lexmark Inkjet Drivers) .En nuestro caso aparece justo ahora la justamente inferior 4900 series , que es la mas cercana al modelo x4850

 

 

 

4900

 

Ya solo bastara pulsar en «Siguiente» ,nos  pedirá un nombre a la impresora,una impresión de prueba  y finalmente concluirá el asistente, con lo cual ya debería volver a poder imprimir en su impresora desde su ordenador con windows 10

 

Si no le ha funcionado lo anterior ,otras  ideas para lograr acceder a su impresora desde w10,  es usando alguno de los siguientes métodos:

1- Lograr compatibilidad con un driver mas antiguo:

Para ello realice los siguientes pasos:

a- Descargar el controlador mas actual disponible aquí

b- Botón derecho sobre el e ingresar en Propiedades/ Compatibilidad

c- Activar compatibilidad y probar de uno a la vez con Windows XP, Windows 7

d- Aplicar los cambios cada vez que elija un modo de compatibilidad.

 

2- Dejar que Windows Update intente buscar el mejor software compatible.

Para ello realice los siguientes pasos:

a- Panel de Control/ Sistemas y Seguridad/ Windows Update

b- Dentro de Windows Update, en la solapa izquierda, ingresar en Cambiar Configuración

c-tildar la segunda opción que dice «ofrecer actualización para otros productos…»

d- Aceptar los cambios con la opción en la parte inferior de dicho menú

e- Windows Update ahora buscará, además, actualizaciones para otros productos Microsoft. Esperar y ver las actualizaciones opcionales que ofrece.

3_  Método de actualizacion de controlador :

a- Debe tener previamente instalado un compresor de archivos como Winrar o Winzip  y descargar el driver para windows 8 desde la pagina oficial de Lexmark

b- Click derecho sobre el archivo descargado y seleccionar extraer archivos y elija una carpeta donde desea extraerlos.

c- Vaya a Equipo , botón derecho sobre algún lugar dentro de dicha carpeta donde no haya íconos, elegir propiedades. Luego de la barra de la izquierda elegir «Administrador de dispositivos». Nota: también puede localizar esta opción utilizando el buscador de Windows 8 y escribiendo «administrador de dispositivos».

d- Ver si la impresora aparece con un signo de interrogación. Botón derecho sobre el y elegir «actualizar controlador…»

e- Probar ambas opciones: Primero por Windows Update y sino volver a hacer lo mismo, seleccionar la otra opción de búsqueda y elegir la carpeta donde extrajimos el archivo descargado. No elegir el archivo descargado sino la carpeta con los archivos descargados y ver si alguno de ellos funciona.

Esperemos que al menos alguno de estos métodos el haya servido , si no es así todavía tiene una ultima oportunidad : puede tener una maquina virtual con una versión inferior de windows e instalar desde el driver oficial sin problemas..