extraer adjuntos de correos EML

Iniciado por adla, 5 Noviembre 2020, 20:27 PM

0 Miembros y 2 Visitantes están viendo este tema.

adla

hola, tengo una carpeta con correos en eml, ¿como puedo hacer un programa para extraerlos todos por lotes en una nueva carpeta?, por favor si teneis algun codigo en vb6 que haga esto o me vale una aplicacion compilada en otro lenguaje que se elija una carpeta y extraiga todos los eml en otra. Gracias

adla

doy mas información, porque no consigo hacerlo, creo que la idea la tengo pero no me centro, estoy con una medicación fuerte para la ansiedad y la depresión que no me deja pensar.

1. la idea es abrir el fichero .eml y recorrerlo hasta encontrar "filename=" que contiene el nombre del adjunto, algo asi:

Private Sub VerContenido(Fichero As String)
    Dim Canal As Integer
    Dim Cadena As String
    Dim NombreArchivo As String
    Dim Contenido As String
    Dim Adjunto As String
    Dim t As Integer

    If Len(Fichero) = 0 Then Exit Sub

    NombreArchivo = ""
    Contenido = ""
    Adjunto = ""

    Canal = FreeFile()
    Open Fichero For Input As #Canal

    Do While Not EOF(Canal)
        'lee una linea del fichero origen
        Line Input #Canal, Cadena

   ' Si la variable NombreArchivo esta vacia el contenido se añade a Contenido
        ' Aqui se guarda todo el mensaje del correo menos los adjuntos en txt
        If NombreArchivo = "" Then Contenido = Contenido + Cadena + Chr$(13) + Chr$(10)
        ' Si se ha encontrado el nombre de un adjunto
        ' el contenido del adjunto se guarda en la variable Adjunto
        If NombreArchivo <> "" Then
            If Cadena <> "" Then
                Adjunto = Adjunto + Cadena
            End If
        End If

   ' Si encontramos "filename=" quiere decir que hay un adjunto
        t = InStr(LCase(Cadena), "filename=")
        If t > 0 Then
            NombreArchivo = Mid$(Cadena, t + 10)
            NombreArchivo = Left(NombreArchivo, Len(NombreArchivo) - 1)
        End If
    Loop
    Close #Canal    ' Cierra el archivo.

End Sub

2. Ahora tenemos dos variables, Contenido con todo el mensaje menos los adjuntos que se guardaria como aguaococacola.txt y la variable Adjunto que contiene el adjunto codificado en Base64, habria que pasar esa codificación a binario y guardarla como aguaococacola.pps, para eso he encontrado estas funciones:

' Codificar y Decodificar en BASE64

Public Function DecodeBase64(ByVal strData As String) As Byte()
    Dim objXML As Object
    Dim objNode As Object

    Set objXML = CreateObject("MSXML2.DOMDocument")
    Set objNode = objXML.createElement("b64")
    objNode.dataType = "bin.base64"
    objNode.Text = strData
    DecodeBase64 = objNode.nodeTypedValue

    Set objNode = Nothing
    Set objXML = Nothing

End Function


Public Function EnecodeBase64(ByVal strData As String) As Byte()
    Dim objStream As Object
    Dim objNode As Object
    Dim objXML As Object
    Dim bArray() As Byte

    Set objStream = CreateObject("ADODB.Stream")

    With objStream
        .Type = 2
        .Open
        .Charset = "unicode"
        .WriteText strData
        .Flush
        .Position = 0
        .Type = 1
        .read (2)
        bArray = .read
        .Close
    End With

    Set objXML = CreateObject("MSXML2.DOMDocument")
    Set objNode = objXML.createElement("b64")

    objNode.dataType = "bin.base64"
    objNode.nodeTypedValue = bArray
    EnecodeBase64 = objNode.Text

    Set objStream = Nothing
    Set objNode = Nothing
    Set objXML = Nothing

End Function

3. Si hay varios adjuntos se tiene que repetir el proceso.

a). Tengo problemas para encontrar el final del adjunto.
b). No sé como pasar la variable Adjunto para que funcione la decodificacion Base64
c). No sé como guardar el archivo Adjunto una vez pasado a binario.

He intentado varias cosas pero todas me dan error. Alguien me puede ayudar  :-(

Gracias, un saludo.

AlbertoBSD

#2
Te puedo ayudar , pero no tengo compilador de VB ni de tecnologías Microsoft en este momento, pasame un archivo EML y con gusto le hecho un ojo para extraer todas los adjuntos, por cierto que ya debería de existir un programa que haga eso no?




Edito ya vi la estructura del archivo y no esta tan complicada.

Pregunta:

Quieres todos los adjuntos incluidos los que aparecen en el body del mensaje como imagenes y demas o solo considerados realmente "attachment" ?

Las imágenes del body y demás tienen un "inline" en el código ejemplo
Content-Disposition: inline; filename="background.gif"

O solo los "attachment"
Content-Disposition: attachment; filename="attachment.txt"


Saludos!
Donaciones
1Coffee1jV4gB5gaXfHgSHDz9xx9QSECVW

adla

#3
Cita de: AlbertoBSD en 10 Noviembre 2020, 15:59 PM
Te puedo ayudar , pero no tengo compilador de VB ni de tecnologías Microsoft en este momento, pasame un archivo EML y con gusto le hecho un ojo para extraer todas los adjuntos, por cierto que ya debería de existir un programa que haga eso no?




Edito ya vi la estructura del archivo y no esta tan complicada.

Pregunta:

Quieres todos los adjuntos incluidos los que aparecen en el body del mensaje como imagenes y demas o solo considerados realmente "attachment" ?

Las imágenes del body y demás tienen un "inline" en el código ejemplo
Content-Disposition: inline; filename="background.gif"

O solo los "attachment"
Content-Disposition: attachment; filename="attachment.txt"


Saludos!

he encontrado esto: https://www.enmimaquinafunciona.com/pregunta/51267/como-extraer-los-datos-adjuntos-de-archivos-eml-con-la-linea-de-comandos-de-windows
pero no funcionan los enlaces..

aqui puedes descargar un zip que contiene un eml con un solo adjunto.. la idea es que extraiga todos los adjuntos, aunque este solo contiene uno. Solo los adjuntos pero si son imagenes tambien, no los logos que tenga el cuerpo.

Muchas gracias Alberto.


AlbertoBSD

#4
Lo hice pero actualmente solo para un solo archivo eml, ya que me da flojera hacerlo para todo un directorio y que busque los archivos eml etc etc etc...

Lo hice en C. se que este es el subforo de VB, pero la verdad VB no me gusta mucho para este tipo de operaciones, de hechos me gusta el VBA para automatizar trabajos en Excel

Imagen de prueba que funciona:


Y el archivo se crea en el directorio pasado como segundo parametro.



Por cierto si el siguiente código fuente si se compila en algunos compiladores de Windows puede dar muchos warning, pero con gcc de MinGW no me tira ningun warning ni error como esta en la imagen.

/*
gcc -o dump_eml.exe dump_eml_attachments.c
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdint.h>

static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
                                'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
                                'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
                                'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
                                'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
                                'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                                'w', 'x', 'y', 'z', '0', '1', '2', '3',
                                '4', '5', '6', '7', '8', '9', '+', '/'};
static char *decoding_table = NULL;
static int mod_table[] = {0, 2, 1};

unsigned char *base64_decode(const char *data,
                             size_t input_length,
                             size_t *output_length);
void build_decoding_table();
void base64_cleanup();

int open_and_extract_from_eml(char *filename,char *path_destino);
int isEmptyLine(char *line);
char *content_disposition = "Content-Disposition: attachment;";

int main(int argc, char **argv ) {
if(argc != 3) {
printf("Uso: %s <Carpeta_con_EMLs> <Carpeta_destino_adjuntos>\n",argv[0]);
exit(0);
}
open_and_extract_from_eml(argv[1],argv[2]);
return 0;
}

int  open_and_extract_from_eml(char *filename,char *path_destino) {
FILE *eml_file, *temp_file;
char *dest_file,*temp0,*temp1;
char *line,*buffer_base64 = NULL,*buffer_decoded;
char *full_writen_file;
int len_dest_file_name,offset,len_content_disposition,len_base64_line,len_base64_buffer, len_output,len_path_destino,entrar;
len_content_disposition = strlen(content_disposition);
len_path_destino = strlen(path_destino);
line = malloc(1024);
eml_file = fopen(filename,"rb");
offset = 0;
while(!feof(eml_file) && fgets(line,1024,eml_file) != NULL) {
if(memcmp(line,content_disposition,len_content_disposition) == 0) {
printf("Encontrado: %s",line);
temp0 = strstr(line,"filename=");
if(temp0 ==NULL ) {
//tal vez la proxima linea?
memset(line,0,1024);
fgets(line,1024,eml_file);
}

temp0 = strstr(line,"filename=");
if(temp0 !=NULL ) {
temp1 = strstr(temp0 +10,"\"");
if(temp1 == NULL) {
//No hay " finales
exit(0);
}
len_dest_file_name = temp1 - (line + (temp0 - line) + 10 );
//printf("len_dest_file_name %i\n",len_dest_file_name);
dest_file = malloc(len_dest_file_name+1);
strncpy(dest_file,(line + (temp0 - line) + 10),len_dest_file_name);
dest_file[len_dest_file_name] = '\0';

memset(line,0,1024);
fgets(line,1024,eml_file);
//printf("Nueva linea leida \"%s\"",line);
if(!isEmptyLine(line)) {
//Deberia de ser una linea vacia;
exit(0);
}
buffer_base64 = NULL;
offset = 0;
memset(line,0,1024);
entrar = 1;
while(entrar && fgets(line,1024,eml_file) != NULL &&  !isEmptyLine(line) ) { //leemos hasta la proxima linea vacia o hasta encontrar un '=' al final de la linea
len_base64_line = strlen(line);
buffer_base64 = realloc(buffer_base64,offset+len_base64_line+1);
if(line[len_base64_line-1] == '\n'  || line[len_base64_line-1] == '\r'){
line[len_base64_line-1] ='\0';
len_base64_line--;
}
if(line[len_base64_line-1] == '\n'  || line[len_base64_line-1] == '\r'){
line[len_base64_line-1] ='\0';
len_base64_line--;
}

memcpy(buffer_base64+offset,line,len_base64_line);
offset+=len_base64_line;
if(line[len_base64_line-1] == '=') {
entrar = 0;
}
memset(line,0,1024);
}
buffer_base64[offset] = '\0';
//printf("Encoded buffer: %s\n",buffer_base64);
len_base64_buffer = strlen(buffer_base64);
buffer_decoded = base64_decode(buffer_base64,len_base64_buffer,&len_output);
buffer_decoded[len_output] = '\0';
/*
printf("OK\n");
printf("Decoded buffer: %s\n",buffer_decoded);
printf("Path destino: %s\n",path_destino);
printf("len_dest_file_name: %i\n",len_dest_file_name);
printf("len_path_destino: %i\n",len_path_destino);
*/
full_writen_file = malloc(len_dest_file_name + len_path_destino+10);
sprintf(full_writen_file,"%s/%s",path_destino,dest_file);
printf("Destino: %s\n",full_writen_file);
temp_file = fopen(full_writen_file,"wb");
fwrite(buffer_decoded,1,len_output,temp_file);
fclose(temp_file);

free(buffer_base64);
free(dest_file);
free(full_writen_file);
}
else {
printf("Se encontro %s, pero no se encontro Filename omitiendo!\n",content_disposition);
}
}
memset(line,0,1024);
}
free(line);
}

int isEmptyLine(char *line) {
if(line[0] == '\0' || line[0] == '\n' || line[0] == '\r')
return 1;
return 0;
}

unsigned char *base64_decode(const char *data,
                             size_t input_length,
                             size_t *output_length) {

    if (decoding_table == NULL) build_decoding_table();

    if (input_length % 4 != 0) return NULL;

    *output_length = input_length / 4 * 3;
    if (data[input_length - 1] == '=') (*output_length)--;
    if (data[input_length - 2] == '=') (*output_length)--;

    unsigned char *decoded_data = malloc(*output_length);
    if (decoded_data == NULL) return NULL;

    for (int i = 0, j = 0; i < input_length;) {

        uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
        uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
        uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
        uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];

        uint32_t triple = (sextet_a << 3 * 6)
        + (sextet_b << 2 * 6)
        + (sextet_c << 1 * 6)
        + (sextet_d << 0 * 6);

        if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
        if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
        if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
    }

    return decoded_data;
}

void build_decoding_table() {
    decoding_table = malloc(256);
    for (int i = 0; i < 64; i++)
        decoding_table[(unsigned char) encoding_table[i]] = i;
}


void base64_cleanup() {
    free(decoding_table);
}


El programa lo puedes utilizar para todo un directorio pero con ayuda de batch creo recordar que existe una instrucción for que te ayuda a procesar todos los archivos de un subdirectorio y pasarlos a un programa.

Saludos!
Donaciones
1Coffee1jV4gB5gaXfHgSHDz9xx9QSECVW

adla

#5
hola, muchas gracias por todo, pero no consigo que me extraiga el adjunto..



no aparece la imagen adjunta, esta aqui http://www.franci.es/tmp/eml-no.jpg

Danielㅤ

#6
Hola, en el primer parámetro tenes que pasar un directorio y vos estás pasando un solo archivo, tenés que indicar un directorio donde estén todos esos archivos que querés procesar.

Además el segundo parámetro le estás indicando una unidad como ubicación pero no una carpeta y es recomendable que crees una carpeta para alojar todos los archivos destinos, por ejemplo el comando podría ser:

"D:\agua o cocacola" "D:\Adjuntos de correos EML"


Saludos
¡Regresando como cual Fenix! ~
Bomber Code © 2021 https://www.bombercode.net/foro/

Ayudas - Aportes - Tutoriales - Y mucho mas!!!

AlbertoBSD

Cita de: adla en 11 Noviembre 2020, 09:05 AM
hola, muchas gracias por todo, pero no consigo que me extraiga el adjunto..

Que tal ya veo algo no esta bien pero no puedo saber que es si no veo el eml que le pasas, si gustas puedes mandarme el EML a mi correo, mi informacion esta por ahi publica
Donaciones
1Coffee1jV4gB5gaXfHgSHDz9xx9QSECVW

adla


Cita de: [D]aniel en 11 Noviembre 2020, 13:49 PM
Hola, en el primer parámetro tenes que pasar un directorio y vos estás pasando un solo archivo, tenés que indicar un directorio donde estén todos esos archivos que querés procesar.

Además el segundo parámetro le estás indicando una unidad como ubicación pero no una carpeta y es recomendable que crees una carpeta para alojar todos los archivos destinos, por ejemplo el comando podría ser:

"D:\agua o cocacola" "D:\Adjuntos de correos EML"


Saludos

no le paso la ruta porque el ejecutable y el archivo estan en la misma carpeta de hecho lo encuentra. He probado poniendo la ruta entera, con la carpeta creada, con la misma carpeta de entrada y con todo lo que se me ha pasado por la cabeza pero he subido solo una imagen. Gracias, Saludos

AlbertoBSD

No se si todos tus eml tengan algún detalle, uno de ellos como te comente por correo estaba "dañado", se supone que deberia de estar X cantidad de información en una línea y en tu archivo tenia un salto de linea en medio eso colgó el programa.

Ya funciona para los ejemplos que me pasaste mira las imágenes





El codigo esta actualizado en el post donde lo publique, en este mismo Hilo.

Saludos
Donaciones
1Coffee1jV4gB5gaXfHgSHDz9xx9QSECVW