Resumen SMTP. Funcionamiento.   (2 mensajes )

Pido perdón de antemano por la extensión de este documento.

Después de estudiar los datos que nos aportó el compañero "Antonio
Guillermo" y de investigar en diversas fuentes he averiguado las reglas a
seguir para enviar correo mediante comandos SMTP, usando el control
"winsock".

Para los que no saben de lo que estoy hablando les diré que se trata de
establecer un dialogo directo entre nuestro programa de VB y el servidor de
correo SMTP (el que gestiona nuestra dirección de correo).

Esto significa que nuestros mensajes irán directamente desde nuestro
programa de Visual Basic al servidor SMTP sin utilizar ningún otro programa
intermedio de correo electrónico.

Antes de nada vale la pena explicar un poco los comandos SMTP mas frecuentes
y las respuestas que debemos esperar del servidor SMTP.

Para los ejemplos usaré como servidor SMTP "smtp.MiProveedor.es" y como
cuenta de correo "Yo@MiProveedor.es"

Como regla general al enviar un comando SMTP debemos esperar una respuesta
del servidor SMTP. Esta respuesta consta de dos partes. La primera es un
número de tres cifras y la segunda es una descripción. Debemos fijarnos en
este número de tres cifras para saber que ha hecho el servidor con nuestro
comando.

Hay una serie de respuestas estándar que nos encontramos siempre y que hacen
referencia a errores. Las descripciones que acompaño son genéricas, y en
cada caso, el servidor nos envía una descripción ajustada al error.

 500 - Comando no reconocido. Error de sintaxis
 501 - Error en los argumentos del parámetro.
 502 - Comando no implementado
 503 - Secuencia de comandos incorrecta
 504 - Argumento no implementado
 550 - Buzón de correo no disponible
 551 - Usuario no es local
 552 - Acción abortada por exceso de datos
 553 - Buzón de correos no accesible
 554 - Transacción fallida

Otras respuestas nos informan de que el comando ha tenido éxito.

 220 - El servidor SMTP nos ha reconocido y esta preparado
 221 - La solicitud de cierre de la comunicación ha sido aceptada
 250 - Solicitud aceptada
 251 - Usuario no es local, pero se acepta el envío
 354 - Acepta el resto de datos que enviemos como texto libre.

Otras respuestas nos informan de otros problemas.

 421 - El servicio no esta disponible.
 450 - Solicitud rechazada. (Por ejemplo: buzón lleno)
 451 - Solicitud abortada. (posible error interno)
 452 - Solicitud no aceptada. (Por ejemplo: disco lleno)

Paso a describir uno a uno los comandos SMTP básicos.

- HELO : Sirve para identificarnos frente al servidor SMTP
ejemplo: "HELO Yo"
Respuestas posibles : 220 - el servidor SMTP nos ha reconocido.
                      500, 501, 504, 421 - Error

- MAIL : Se usa para iniciar una transacción de correo y contiene la
dirección de respuesta. Esta dirección de respuesta se usará para el envío
de noticias al emisor a posteriori.
Ejemplo: "MAIL FROM: <Yo@MiProveedor.es>"
Respuestas posibles : 250 - Solicitud aceptada
                      552, 451, 452 - Fallo
                      500, 501, 421 - Error

- RCPT : Se usa para indicar el receptor del mensaje. Si se quieren
especificar múltiples receptores, se debe enviar este comando múltiples
veces.
Ejemplo: "RCPT TO:<Tu@TuProveedor.es>"
Respuestas posibles : 250, 251 - Solicitud aceptada
                      550, 551, 552, 553, 450, 451, 542 - Fallo
                      500, 501, 421 - Error

- RSET : Indica que se debe abortar el mensaje actual.
Ejemplo: "RSET"
Respuestas posibles : 250 - Solicitud aceptada
                      500, 501, 504, 421 - Error


- DATA : Indica que las líneas siguientes que se envíen no se procesaran
como comandos sino como texto libre. Este texto libre puede contener
cualquiera de los 128 caracteres ASCII. Cuando enviemos una línea con un
punto solo, el servidor SMTP interpretará que se ha terminado el mensaje
Ejemplo: "DATA"
         "Hola Pedro. bla, bla, bla" (*)
         "bla, bla" (*)
         "bla, bla" (*)
         "."
Resp.posibles de "DATA" : 354 - Acepta resto de líneas como texto
                          451, 554 - Fallo
                          500, 501, 503, 421 - Error
Resp.posibles de "." : 250 - Mensaje aceptado
                       552, 554, 451, 452 - Fallo

(*) Estas líneas de texto libre no devuelven ningún tipo de código.

- QUIT : Cierra la comunicación con el servidor SMTP.
Ejemplo: "QUIT"
Respuestas posibles : 221 - Solicitud aceptada
                      500 - Error

Como norma general podemos decir que los códigos 2xx y 3xx significan que el
comando se ha procesado bien y los códigos 4xxx y 5xx que ha fallado.
Por este motivo podemos generalizar y fijarnos solo en el primer dígito para
conocer el resultado del comando.

Para proceder a construir nuestro programa de correo, necesitaremos un
"FORM" con el control "Winsock". A este control le llamaremos "Sck"

Lo primero que haremos antes de enviar nada es abrir una línea de
comunicaciones entre nosotros y el servidor SMTP.

Pondremos el siguiente código en el botón que usemos para lanzar el mensaje:

         Sck.Protocol = sckTCPProtocol
         Sck.RemotePort = 25
         Sck.RemoteHost = "smtp.MiProveedor.es"
         Sck.Connect

Si no consigue conectar se activará el evento

         Sck_Error

Este evento nos proporciona información acerca de la naturaleza del
problema. Podemos consultar las variables "Number" y "Description".

Cuando la conexión se haya completado recibiremos el evento

         Sck_Connect

y a la vez recibiremos el código 220.

Para comprobar que efectivamente recibimos este código nos guiaremos por el
evento

         Sck_DataArrival

y lo recogeremos con "Sck.GetData Variable"

En este momento ya estamos en disposición de enviar nuestro primer comando
SMTP.

         Sck.SendData ("MAIL FROM: <Yo@MiProveedor.es>" & vbCrLf)

Sabremos que los datos se han enviado por completo cuando recibamos el
evento

         Sck.SendComplete

Ahora solo falta esperar la respuesta del servidor SMTP, que la recogeremos
en el evento

         Sck_DataArrival

con "Sck.GetData Variable"

Si recibimos un 250, sabremos que nuestra petición ha sido aceptada y
continuaremos. Si no, enviaremos un "RSET" para cancelar el mensaje. Algo ha
ido mal.

Siguiendo este mismo procedimiento enviaremos el resto de comandos mientras
recibamos los códigos 2xx y 3xx.

         Sck.SendData ("RCPT TO: <Tu@TuProveedor.es>" & vbCrLf)
         Sck.SendData ("DATA" & vbCrLf)
         Sck.SendData ("Apreciado amigo" & vbCrLf)
         Sck.SendData ("bla, bla" & vbCrLf)
         Sck.SendData ("bla, bla" & vbCrLf)
         Sck.SendData ("bla, bla" & vbCrLf)
         Sck.SendData ("bla, bla" & vbCrLf)
         Sck.SendData ("." & vbCrLf)

Si todo ha ido bien podríamos volver a comenzar y enviar otro mensaje

         Sck.SendData ("MAIL FROM: <Yo@MiProveedor.es>" & vbCrLf)
         Sck.SendData ("RCPT TO: <Tu@TuProveedor.es>" & vbCrLf)
         Sck.SendData ("DATA" & vbCrLf)
         Sck.SendData ("Apreciado amigo" & vbCrLf)
         Sck.SendData ("bla, bla" & vbCrLf)
         Sck.SendData ("bla, bla" & vbCrLf)
         Sck.SendData ("bla, bla" & vbCrLf)
         Sck.SendData ("bla, bla" & vbCrLf)
         Sck.SendData ("." & vbCrLf)

Al finalizar el envío de todos los mensajes deberemos enviar un comando
"QUIT" y cerrar el canal con Sck.Close

Debemos tener presente que una vez enviado el comando "DATA", el servidor
SMTP no es capaz de entender ningún comando más que el de final de mensaje
".".

Existe una restricción en cuanto al tamaño de los mensajes se refiere.
- Direcciones de correo: como máximo 256 caracteres.
- Nombre del usuario: como máximo 64 caracteres.
- Línea de comandos incluyendo el comando, los parámetros y el : como
máximo 512 caracteres.
- Línea de respuesta del servidor SMTP incluyendo el código y el :
como máximo 512 caracteres.
- Línea de texto incluyendo : 1000 caracteres.
- Destinatarios del mensaje: Como máximo 100 destinatarios simultáneos.

Si en algún momento excediésemos estos valores recibiremos alguno de estos
mensajes
500 - Línea demasiado larga
501 - Dirección demasiado larga
552 - Demasiados destinatarios
552 - Línea de mensaje demasiado larga

Bueno, por ahora os dejo para que dijerais toda esta información.
En próximos días os enviaré más.

Un saludo

====================
Raúl Giménez Fuentes
raulgimenez@redestb.es
ICQ #4332550
Barcelona-España
====================

------------ PROBANDO SMTP ---------------

Os explico una manera de probar si los comandos SMTP que estamos enviando
desde nuestro programa de VB son correctos.
Por lo menos, a mi me ha sido muy útil para depurar mis programa y para
entender mejor el funcionamiento de este protocolo de comunicaciones.

Para realizar estas pruebas usaremos el programa TELNET que encontraremos en
el directorio Windows.

Una vez arrancado el programa TELNET debemos iniciar una sesión. Como Host
pondremos nuestro servidor SMTP (por ejemplo "smtp.MiProveedor.es" y como
puerto el 25. En las preferencias de terminal, activaremos el "eco local" en
caso de que no veamos lo que escribimos.

Al iniciar la sesión, nos debe aparecer un mensaje similar a este:

220 cinet.fcr.es ESMTP Sendmail 8.8.8/8.8.8; Thu, 24 Sep 1998 01:33:24 +0200

A partir de aquí ya podemos comenzar a escribir los comandos SMTP.
El primero puede ser "HELP", que nos informará de los comandos disponibles.

A continuación os presento una sesión TELNET de ejemplo.

SMTP> 220 cinet.fcr.es ESMTP Sendmail 8.8.8/8.8.8; Thu, 24 Sep 998 01:33:24
+0200 (CEST)
YO > HELO raul
SMTP> 250 cinet.fcr.es Hello ppp174.202.redestb.es [195.122.202.174],
pleased to meet you
YO > MAIL FROM:<raulgimenez@redestb.es>
SMTP> 250 Sender <raulgimenez@redestb.es> Ok
YO > RCPT TO:<alguien@redestb.es>
SMTP> 250 Recipient <alguien@redestb.es> Ok
YO > RCPT TO:<otroalguien@redestb.es>
SMTP> 250 Recipient <otroalguien@redestb.es> Ok
YO > DATA
SMTP> 354 Ok Send data ending with .
YO > Aqui empieza el mensaje
YO > Bla, Bla, Bla
YO > Bla, bla
YO > Bla
YO > .
SMTP> 250 Message received: 19980923234010927.AAA212@raulgimenez
YO > QUIT
SMTP> cinet.fcr.es closing connection


-------- PARTES DE UN MENSAJE ----------

Se puede decir que un mensaje esta formado por dos partes. La cabecera y el
cuerpo.
La cabecera la forman los comandos "MAIL FROM" y "RCPT TO" y el cuerpo es
todo lo que se encuentra entre "DATA" y "."

Pues bien, dentro del cuerpo podemos encontrar una serie de sub-comandos que
informan acerca del tipo de contenido del mensaje.
Por ejemplo para enviar un texto que contenga cualquier carácter ASCII de 8
bits podemos seguir el siguiente ejemplo.

         MAIL FROM: <Yo@MiProveedor.es>
         RCPT TO: <Tu@TuProveedor.es>
         DATA
         MIME-Version: 1.0
         Content-Type: text/plain;
         "charset="iso-8859-1"
         Content-Transfer-Encoding: 8bit
         
         Esto es el mensaje
         Bla, bla
         Bla, bla
         .

No existe ningún comando para enviar ficheros anexados de forma automática,
pero si podemos diseñar una herramienta que lo haga.
No es difícil.
Como debéis saber, los mensajes sólo pueden contener caracteres ASCII.
Lo que hay que hacer es enviar el fichero dentro del cuerpo del mensaje como
si fuese texto.
Para ello debemos codificar el contenido del anexo a un formato que solo
contenga caracteres ASCII.
Uno de los formato posibles es BASE64.

La codificación base64 transforma 3 grupos de 8 bits (24 bits en total) en 4
grupos de 6 bits. Cada unos de estos grupos de 6 bits toman valores de 0 a
64.
Y se codifican de la siguiente manera.

        0=A 17=R 34=i 51=z
        1=B 18=S 35=j 52=0
        2=C 19=T 36=k 53=1
        3=D 20=U 37=l 54=2
        4=E 21=V 38=m 55=3
        5=F 22=W 39=n 56=4
        6=G 23=X 40=o 57=5
        7=H 24=Y 41=p 58=6
        8=I 25=Z 42=q 59=7
        9=J 26=a 43=r 60=8
       10=K 27=b 44=s 61=9
       11=L 28=c 45=t 62=+
       12=M 29=d 46=u 63=/
       13=N 30=e 47=v
       14=O 31=f 48=w (pad) =
       15=P 32=g 49=x
       16=Q 33=h 50=y

El resultado de la codificación debe representarse en líneas de no más de 76
caracteres.
Existe un tratamiento especial si al final de los datos disponemos de menos
de 3 grupos de 8 bits (24 bits)
1) Si solo tenemos 1 grupo (8 bits) que codificar, lo codificaremos y
añadiremos al final dos "="
2) Si solo tenemos 2 grupos (16 bits) que codificar, los codificaremos y
añadiremos un "=".

Con un ejemplo lo veremos mas claro.
Supongamos que tenemos un archivo JPG cuyo contenido en binario es: (separo
cada 8bits con un guión)

01001000-01001111-01001100-01000001-00100000-01000001-01001101-01001001-0100
0111-01001111

Si vamos tomando grupos de 8 bits de 3 en 3 y los codificamos de esta manera
al final nos queda 1 grupo suelto.
Por ello, aplicando el tratamiento especial 1) debemos añadir dos "=",


Primer grupo de 24 bits (transformación)
========================================
Binario.(Grupos de 8bits): 01001000-01001111-01001100
Binario.(Grupos de 6bits): 010010-000100-111101-001100
Decimal..................: --18----04-----61------12-
CODIFICADO Base 64.......: --S------E------9------M--


Segundo grupo de 24 bits (Transformación)
========================================
Binario.(Grupos de 8bits): 01000001-00100000-01000001
Binario.(Grupos de 6bits): 010000-010010-000001-000001
Decimal..................: --16-----18-----01-----01-
CODIFICADO Base 64.......: --Q------S------B------B--


Tercer grupo de 24 bits (Transformación)
========================================
Binario.(Grupos de 8bits): 01001101-01001001-01000111
Binario.(Grupos de 6bits): 010011-010100-100101-000111
Decimal..................: --19----21------37-----07-
CODIFICADO Base 64.......: ---T-----U------l------H--


8 bits restantes (Transformación)
=================================
Binario............(8 bits): 01001111
Binario.(2 Grupos de 6bits): 010011-11 (añadimos 4 ceros ficticios) 0000
Decimal....................: --19-----48--
CODIFICADO Base 64.........: ---T---w (añadimos "==")


De esta manera este fichero JPG se convierte en "SE9NQSBBTUlHTw=="

Ahora solo queda la parte final.
¿ Como enviar este fichero como un anexo de nuestro mensaje ?

Pues deberíamos enviar un mensaje como este.
(Nota: sustituir por el carácter tabulador)

   MAIL FROM: <Yo@MiProveedor.es>
   RCPT TO: <Tu@TuProveedor.es>
   DATA
   MIME-Version: 1.0
   Content-Type: multipart/mixed;
   boundary="----=_NextPart_000_0004_01BD358C.1AD67DC0"

   Aqui podemos poner comentarios que no se mostrarán.
   Acerca de nosotros, de nuestros programas, etc...

   ------=_NextPart_000_0004_01BD358C.1AD67DC0
   Content-Type: text/plain;
   charset="iso-8859-1"
   Content-Transfer-Encoding: 8bit

   Aqui pondremos el cuerpo del mensaje. Solo texto.

   ------=_NextPart_000_0004_01BD358C.1AD67DC0
   Content-Type: image/jpeg;
   Name="dibujo.jpg"
   Content-Transfer-Encoding: base64
   Content-Disposition: attachment;
   filename="dibujo.jpg"

   SE9NQSBBTUlHTw==

   ------=_NextPart_000_0004_01BD358C.1AD67DC0--


Os explico un poco cada una de las partes del mensaje

Content-Type: multipart/mixed;
 Esta línea nos indica que el mensaje está compuesto por varias partes de
diferentes naturalezas.
 En nuestro caso las partes son, un texto y un fichero gráfico JPG.

boundary="----=_NextPart_000_0004_01BD358C.1AD67DC0"
 La primera aparición de esta línea nos indica cual será el separador entre
las partes.
 Los caracteres que aparecen entre comillas nos los podemos inventar. Solo
debemos de procurar que sean lo suficientemente rebuscados como para que no
puedan aparecer en ninguna parte del mensaje de forma casual.

------=_NextPart_000_0004_01BD358C.1AD67DC0
 las siguientes veces que aparece esta línea nos indica que aquí finaliza
una de las partes y comienza la otra o que finaliza el mensaje.
 Observad que consta del literal que aparece en el "boundary" precedido de
dos guiones.


Dentro de cada una de las partes del mensaje encontramos a su vez una
subcabecera donde nos informa del tipo de elemento que hay debajo

Name="dibujo.jpg"
filename="dibujo.jpg"
 Nos informan del nombre del fichero anexado.
 Aun no he descubierto la diferencia entre ambos.

Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 Nos informan de que es un anexo y que está codificado en BASE64.

En general, en el apartado "Content-Type" podemos encontrar los siguientes
valores "tipo/subtipo"
tipos posibles ={application, audio, image, message, multipart, text, video}
Subtipos para "application"={octet-stream}
subtipos para "audio"={basic}
Subtipos para "image"={gif, jpeg}
Subtipos para "multipart"={mixed, parallel, digest, alternative}
Subtipos para "text"={plain}
Subtipos para "video"={mpeg}

Es casi imposible contemplar y explicar todos los casos y combinaciones
posibles. Cuando tengáis alguna duda, lo mejor es acudir a vuestros propios
mensajes y echarles un vistazo en su forma original. Es muy constructivo y
ayuda en gran medida a hacerse una idea del funcionamiento del SMTP.

Os animo a seguir investigando y a complementar estas notas si encontráis
novedades al respecto

Un saludo

====================
Raúl Giménez Fuentes
(Nik:Atawalabachala)
raulgimenez@redestb.es
ICQ #4332550
Barcelona-España
====================



Resumen Resumen

Visual Basic Página de Visual Basic

Página principal Página principal

www.jrubi.com