Carga de e-mails a servidor FTP con C#
Después de pelear por unos días con este problema, ya esta resuelto, aunque no de la forma en que quería inicialmente pero la solución al problema esta funcionando sin problemas y ahora publicaré el código que resolvía este pequeño gran problema. La idea inicial era crear un Complemento de Outlook en VS .Net y escribir todo el código en él, pero tuve un problema, por alguna razón que hasta el momento desconozco, los eventos de mi complemento de outlook dejaron de funcionar, no los reconocía el programa, cargaba el outlook, pero no “aparentemente” no pasaba por ningún evento, de manera que no pude crear el complemento porque ningún código que escribía era reconocido, nunca se ejecutaba.
Por este motivo tuve que separar el programa en dos “sub programitas” que a continuación detallaré:
El escenario: Se requería un programa que guardáse los correos electrónicos entrantes recibidos en un MS Outlook 2003 en una carpeta de un servidor web pero deben subir de forma que una aplicación web externa los pueda leer como archivos independientes, es decir, deben subir como archivos de texto plano. Bien, separemos el problema en dos partes:
- El mensaje de correo debe guardarse como un archivo de texto en una carpeta del computador local.
- El archivo creado debe subir al servidor web en una carpeta específica dependiendo del número que figura en el subject de forma automática. Es decir, si hay 3 archivos que incluyen el número 5 en el subject, los 3 archivos se deben grabar en una carpeta de nombre 5 en el servidor web. Si la carpeta no existe, se debe crear automáticamente.
Ya que el complemento para Outlook no funcionaba conmigo, no me quedó otra alternativa que escribir el código necesario para grabar el correo entrante en una carpeta como una macro de VBA en la ventana de código del Outlook 2003 (pulsando la combinación de teclas ALT + F11).
El código que escribí es el siguiente:
Option Explicit
Private Sub Application_NewMail()
Dim fs As Object, a As Object
Dim subject As String‘Objeto Folder de MAPI (INBOX)
Dim objInbox As MAPIFolder
Set objInbox = Application.GetNamespace(“MAPI”).GetDefaultFolder(olFolderInbox)
‘Objeto Email
Dim objMensaje As MailItem
With objInbox.Items
If .Count = 0 Then Exit Sub
Set objMensaje = .Item(.Count)
End With
With objMensaje
Set fs = CreateObject(“Scripting.FileSystemObject”)
subject = Replace(Trim(.subject), “:”, “-”)
Set a = fs.CreateTextFile(“D:\MailsGrabados\” & Trim(subject) & ” .txt”, True)
a.WriteLine (.Body)
a.Close
End With
End Sub
Como ven, escribí el código en el evento Application_NewMail() para que este código se ejecute cada vez que llegase un correo y según se ve en el código anterior se guarda en una carpeta llamada MailsGrabados en la unidad D. Esta primera parte, funciona sin problemas. Como esto estará en una PC en particular no me preocupo por si la carpeta MailsGrabados exista o no, pero en realidad debería hacer una validación para eso, pero como ya me cansé, lo hacen Uds.
Para el segundo caso, he utilizado un Servicio Windows con un FileSystemWatcher (esta clase permite vigilar los cambios que se producen en un directorio en particular del SO) para “vigilar” una carpeta y cada vez que se crean archivos los suba al servidor web. Bueno, para crear el servicio basta con abrir la pantalla del Visual Studio .Net, crear un nuevo proyecto, escoger el tipo de proyecto Windows y luego seleccionar la plantilla Servicio de Windows. En mi caso yo usaré el lenguaje C#. Un servicio de windows es un proceso que corre en segundoplano, de manera que no tiene interfaz gráfica, solo verán una pantalla grsi que dice mas o menos: “Para agregar componentes a la clase, arrástrelos …bla bla bla, etc.” para escribir el código hagan clic derecho sobre esa pantalla gris y escojan la opción Ver código, luego escriban lo siguiente para hacer la carga del archivo:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;namespace UploadService
{
public partial class UploadMailPCO : ServiceBase
{
public UploadMailPCO()
{
InitializeComponent();
}protected override void OnStart(string[] args)
{
string rutaVigilada = @”D:\MailsGrabados\” ;// Verificar que el directorio exista
if(!Directory.Exists(rutaVigilada))
Directory.CreateDirectory(rutaVigilada);//Vigilar los nuevos archivos creados en el directorio de carga
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = rutaVigilada;
//Si se crea un nuevo archivo se invoca al método indicado
watcher.Created += new FileSystemEventHandler(archivo_creado);
watcher.EnableRaisingEvents = true;
}//Este es un método personalizado que se debe escribir en el servicio
static void archivo_creado(object sender, FileSystemEventArgs e)
{
string url = ““ftp://miservidor/midirectorio/”;
string usuario = “user”;
string password = “pass”;//Esta clase se usa para registrar en el log del Sistema Operativo las acciones realizadas
//en el proceso de carga de los archivos.
EventLog log = new EventLog(“SubirArchivoPCO”);
log.Source = “SubirArchivoPCO”;using (MemoryStream mso = new MemoryStream())
{
using (StreamWriter sw = new StreamWriter(mso, Encoding.ASCII))
{
FileStream fso = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read);string modelo = e.Name;
int posIni = modelo.IndexOf(“-”, 0) + 2;
int posFin = modelo.IndexOf(” “, posIni + 1);
string numOC = modelo.Substring(posIni, posFin – posIni);try
{
//Se el directorio correspondiente al número de documento no existe
if (!Directory.Exists(url + numOC))
{
//Implementar un cliente de protocolo de trasferencia ftp
FtpWebRequest ftpMK = (FtpWebRequest)FtpWebRequest.Create(url + numOC);
//Autenticar al usuario en el servidor ftp
ftpMK.Credentials = new NetworkCredential(usuario, password);
//que se cierre la conexion al terminar la operación
ftpMK.KeepAlive = false;
//Indicamos el método crear archivo en este caso
ftpMK.Method = WebRequestMethods.Ftp.MakeDirectory;
//Devolver la respuesta del servidor
ftpMK.GetResponse();
}
FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(url + numOC + “/” + e.Name);
ftp.Credentials = new NetworkCredential(usuario, password);
ftp.KeepAlive = false;
ftp.Method = WebRequestMethods.Ftp.UploadFile;
//Indicamos el tipo de datos binario para utilizarl al enviar el archivo
ftp.UseBinary = true;
ftp.ContentLength = fso.Length;
ftp.Proxy = null;
mso.Position = 0;int buffLenght = 2048;
byte[] buff = new byte[buffLenght];
int contentLen;//Escribir el archivo en el directorio creado
using (Stream strm = ftp.GetRequestStream())
{
contentLen = fso.Read(buff, 0, buffLenght);while (contentLen != 0)
{
strm.Write(buff, 0, contentLen);
contentLen = mso.Read(buff, 0, buffLenght);
}
}
//Escribir en el log si la carga se ha efectuado sin problemas
log.WriteEntry(“Se ha hecho la carga del archivo “ + e.Name + ” de forma correcta”, EventLogEntryType.Information);
}
catch (Exception ex)
{
//Escribir en el log el mensaje si se ha producido un error en la carga
string mensaje = “Se ha producido un error al intentar cargar el archivo “ + e.Name +
” desde la ruta “ + e.FullPath + “. El mensaje de error es el siguiente: “ + ex.Message;
log.WriteEntry(mensaje, EventLogEntryType.Error);
}
}
}
}
}
}
Una vez hecho todo esto, solo necesitamos instalar el servicio y ejecutarlo. Regresamos a la ventana gris del servicio y hagan clic derecho y luego seleccionen la opción Agregar Instalador, se debe haber agregado un archivo de tipo instalador, vamos a configurarlo.
Seleccione el elemento ServiceProcessInstaller y cambie el valor de su propiedad Account a LocalSystem. Luego seleccione el serviceInstaller y cambie las propiedades DisplayName (el nombre que se verá en la ventana de servicios de windows) y Description (la descrición de lo que hace el servicio). Ahora genere el proyecto completo desde el menú Generar.
Ya esta casi listo, solo nos falta instalar el servicio y ejecutarlo, para instalarlo basta con ir al menú Inicio / Todos los programas / Microsoft Visual Studio 2005 / Visual Studio Tools / Símbolo del sistema de Visual Studio 2005 y en la consola (ventana de DOS) cambiar al directorio en donde se ha generado el proyecto (si no le han cambiado el nombre se debe llamar WindowsService1) y escribir installUtil WindowsService1.exe.
Listo!!!! con eso esta terminado, si desean desinstalar el servicio solo escriben installUtil /u WindowsService1, y ahora para que funcione, vayan al panel de control / herramientas administrativas y luego servicios, busquen su servicio en la ventana derecha y luego clic derecho Iniciar.
Espero que les sirva y lo valoren porque me demoré mucho poniéndole colorcitos al código fuente
, si alguien cree que el código puede mejorar (supongo que si se puede) pues en buena hora, envíenme sus propuestas.
Saludos.

esta muy bueno tu codigo me sirvio de mucho!! si me pudieras ayudar de como hago para crear y copiar carpetas por medio de una consola en c#.net te lo agradeceria un monton… me lo mandas a mi correo por fa si pudieras ayudar es q lo estoy ocupando urgente gracias…!!
Gracias tio, me ha servido de mucho este código, aunque en realidad solo he utilizado la parte de crear directorios en el FTP.
Muy bien explicao.
Socio la verdad esta bueno pero ahora me trabo en una cosa
mira tengo una gente qeu pone imagenes en una carpeta de un servidor, ftp donde tengo colgado el sitio.
bueno tengo que mostrar las imagenes que estan ahi, el lio es que es dinamico, es decir hoy hay 3 imagenes y mañana me ponen 20 entonces lo que necesito es leer en la carpeta esa y de alguna manera me de el listado de ficheros qeu tiene para mostrarlos despues.
estoy utilizanto visual studio 2005.
si puedes ayudarme cuanto antes con eso…
gracias