tls example java ssl imap javamail

javamail tls example



JavaMail IMAP sobre SSL bastante lento-Recopilación masiva de múltiples mensajes (3)

Debe agregar un FetchProfile a la bandeja de entrada antes de recorrer los mensajes. El mensaje es un objeto de carga lenta, volverá al servidor para cada mensaje y para cada campo que no se proporcionó con el perfil predeterminado. p.ej

for (Message message: messages) { message.getSubject(); //-> goes to the imap server to fetch the subject line }

Si desea mostrar como una lista de la bandeja de entrada de decir solo De, Asunto, Enviado, Adjunto, etc., usaría algo como lo siguiente

inbox.open(Folder.READ_ONLY); Message[] messages = inbox.getMessages(start + 1, total); FetchProfile fp = new FetchProfile(); fp.add(FetchProfile.Item.ENVELOPE); fp.add(FetchProfileItem.FLAGS); fp.add(FetchProfileItem.CONTENT_INFO); fp.add("X-mailer"); inbox.fetch(messages, fp); // Load the profile of the messages in 1 fetch. for (Message message: messages) { message.getSubject(); //Subject is already local, no additional fetch required }

Espero que ayude.

Actualmente estoy tratando de usar JavaMail para recibir correos electrónicos de servidores IMAP (Gmail y otros). Básicamente, mi código funciona: de hecho puedo obtener los encabezados, el contenido del cuerpo, etc. Mi problema es el siguiente: cuando se trabaja en un servidor IMAP (sin SSL), básicamente se requieren 1-2ms para procesar un mensaje. Cuando voy a un servidor IMAPS (por lo tanto, con SSL, como Gmail) llego a alrededor de 250 m / mensaje. SOLO mido el tiempo al procesar los mensajes (la conexión, el protocolo de enlace y demás NO se tienen en cuenta).

Sé que ya que es SSL, los datos están encriptados. Sin embargo, el tiempo de descifrado no debería ser tan importante, ¿verdad?

He intentado establecer un valor de ServerCacheSize más alto, un tamaño de pool de conexión más alto, pero me estoy quedando sin ideas. ¿Alguien enfrentado con este problema? Resuelto que uno podría esperar?

Mi temor es que la API de JavaMail use una conexión diferente cada vez que busque un correo desde el servidor IMAPS (que involucra la sobrecarga del handshake ...). Si es así, ¿hay alguna manera de anular este comportamiento?

Aquí está mi código (aunque bastante estándar) llamado desde la clase Main ():

public static int connectTest(String SSL, String user, String pwd, String host) throws IOException, ProtocolException, GeneralSecurityException { Properties props = System.getProperties(); props.setProperty("mail.store.protocol", SSL); props.setProperty("mail.imaps.ssl.trust", host); props.setProperty("mail.imaps.connectionpoolsize", "10"); try { Session session = Session.getDefaultInstance(props, null); // session.setDebug(true); Store store = session.getStore(SSL); store.connect(host, user, pwd); Folder inbox = store.getFolder("INBOX"); inbox.open(Folder.READ_ONLY); int numMess = inbox.getMessageCount(); Message[] messages = inbox.getMessages(); for (Message m : messages) { m.getAllHeaders(); m.getContent(); } inbox.close(false); store.close(); return numMess; } catch (MessagingException e) { e.printStackTrace(); System.exit(2); } return 0; }

Gracias por adelantado.


Después de mucho trabajo y la asistencia de las personas en JavaMail, la fuente de esta "lentitud" es el comportamiento de FETCH en la API. De hecho, como dijo pjaol, volvemos al servidor cada vez que necesitamos información (un encabezado o contenido del mensaje) para un mensaje.

Si FetchProfile nos permite obtener información de encabezado de captura masiva, o indicadores, para muchos mensajes, NO es directamente posible obtener el contenido de varios mensajes.

Afortunadamente, podemos escribir nuestro propio comando IMAP para evitar esta "limitación" (se hizo de esta manera para evitar errores de falta de memoria: recuperar todos los correos de la memoria en un comando puede ser bastante pesado).

Aquí está mi código:

import com.sun.mail.iap.Argument; import com.sun.mail.iap.ProtocolException; import com.sun.mail.iap.Response; import com.sun.mail.imap.IMAPFolder; import com.sun.mail.imap.protocol.BODY; import com.sun.mail.imap.protocol.FetchResponse; import com.sun.mail.imap.protocol.IMAPProtocol; import com.sun.mail.imap.protocol.UID; public class CustomProtocolCommand implements IMAPFolder.ProtocolCommand { /** Index on server of first mail to fetch **/ int start; /** Index on server of last mail to fetch **/ int end; public CustomProtocolCommand(int start, int end) { this.start = start; this.end = end; } @Override public Object doCommand(IMAPProtocol protocol) throws ProtocolException { Argument args = new Argument(); args.writeString(Integer.toString(start) + ":" + Integer.toString(end)); args.writeString("BODY[]"); Response[] r = protocol.command("FETCH", args); Response response = r[r.length - 1]; if (response.isOK()) { Properties props = new Properties(); props.setProperty("mail.store.protocol", "imap"); props.setProperty("mail.mime.base64.ignoreerrors", "true"); props.setProperty("mail.imap.partialfetch", "false"); props.setProperty("mail.imaps.partialfetch", "false"); Session session = Session.getInstance(props, null); FetchResponse fetch; BODY body; MimeMessage mm; ByteArrayInputStream is = null; // last response is only result summary: not contents for (int i = 0; i < r.length - 1; i++) { if (r[i] instanceof IMAPResponse) { fetch = (FetchResponse) r[i]; body = (BODY) fetch.getItem(0); is = body.getByteArrayInputStream(); try { mm = new MimeMessage(session, is); Contents.getContents(mm, i); } catch (MessagingException e) { e.printStackTrace(); } } } } // dispatch remaining untagged responses protocol.notifyResponseHandlers(r); protocol.handleResult(response); return "" + (r.length - 1); } }

La función getContents (MimeMessage mm, int i) es una función clásica que imprime de forma recursiva el contenido del mensaje en un archivo (hay muchos ejemplos disponibles en la red).

Para evitar errores de falta de memoria, simplemente establezco un límite de maxDocs y maxSize (¡esto se ha hecho de manera arbitraria y probablemente se puede mejorar!) Que se usa de la siguiente manera:

public int efficientGetContents(IMAPFolder inbox, Message[] messages) throws MessagingException { FetchProfile fp = new FetchProfile(); fp.add(FetchProfile.Item.FLAGS); fp.add(FetchProfile.Item.ENVELOPE); inbox.fetch(messages, fp); int index = 0; int nbMessages = messages.length; final int maxDoc = 5000; final long maxSize = 100000000; // 100Mo // Message numbers limit to fetch int start; int end; while (index < nbMessages) { start = messages[index].getMessageNumber(); int docs = 0; int totalSize = 0; boolean noskip = true; // There are no jumps in the message numbers // list boolean notend = true; // Until we reach one of the limits while (docs < maxDoc && totalSize < maxSize && noskip && notend) { docs++; totalSize += messages[index].getSize(); index++; if (notend = (index < nbMessages)) { noskip = (messages[index - 1].getMessageNumber() + 1 == messages[index] .getMessageNumber()); } } end = messages[index - 1].getMessageNumber(); inbox.doCommand(new CustomProtocolCommand(start, end)); System.out.println("Fetching contents for " + start + ":" + end); System.out.println("Size fetched = " + (totalSize / 1000000) + " Mo"); } return nbMessages; }

No es así que aquí estoy usando números de mensajes, que son inestables (estos cambian si los mensajes se borran del servidor). Un mejor método sería usar UIDs! Luego cambiarías el comando de FETCH a UID FETCH.

Espero que esto ayude!


El tiempo total incluye el tiempo requerido en las operaciones criptográficas. Las operaciones criptográficas necesitan una sembradora aleatoria. Existen diferentes implementaciones de siembra aleatoria que proporcionan bits aleatorios para su uso en la criptografía. De forma predeterminada, Java usa / dev / urandom y esto se especifica en su java.security de la siguiente manera:

securerandom.source=file:/dev/urandom

En Windows, java usa la funcionalidad semilla de Microsoft CryptoAPI que generalmente no tiene problemas. Sin embargo, en Unix y Linux, Java, por defecto usa / dev / random para la siembra aleatoria. Y las operaciones de lectura en / dev / random a veces bloquean y tardan mucho tiempo en completarse. Si está utilizando las plataformas * nix, el tiempo dedicado a esto se contabilizará en el tiempo total.

Como no sé qué plataforma está utilizando, no puedo decir con seguridad que este podría ser su problema. Pero si es así, entonces esta podría ser una de las razones por las que sus operaciones llevan mucho tiempo. Una de las soluciones a esto podría ser usar / dev / urandom en lugar de / dev / random como su sembradora aleatoria, que no bloquea. Esto se puede especificar con la propiedad del sistema "java.security.egd". Por ejemplo,

-Djava.security.egd=file:/dev/urandom

La especificación de esta propiedad del sistema anulará la configuración securerandom.source en su archivo java.security. Puedes darle una oportunidad. Espero eso ayude.