// EmailSender.vdm // Extract e-mail Addresses & Display-Names from e-mail files ("From:" addresses) // Sorts addresses and remove duplicate Address/Name entries. // The e-mail Addresses & Display-Name will be appended to file in the default directory. // This is designed to be used in conjunction with the Wildfile macro. // This macro should work with any MIME Email files. // Includes code to skip the body of multipart MIME, to minimise spurious hits in forwarded attachments. // I use Thunderbird, data is in files without extension e.g. "Inbox" // These are normally located in directory:- // %APPDATA%\Thunderbird\Profiles\default\????????.slt\Mail\???????? // (See Tools/Account Settings/Server Settings/Local Directory for location.) // Works with email Saved from Outlook Express. // (You can select a group of emails and drag them into a directory in Windows Explorer. // This creates a series of .eml files with their names being the subject lines of each email.) // Author:- // Ian Binnie // 13/03/2006 Reg_Set(80,"EmailSender.txt") // <============ Output File Config( D_DSP_WRAP, 0,LOCAL ) // Needed to capture end of long lines #104=Buf_Num // Current Edit Buffer Begin_Of_File() while(!At_EOF) { reg_empty(24) reg_empty(25) reg_empty(26) // To use Reply-To: addresses change Search String to:- "|<|{From:,Content-Type:,Reply-To:}|w" Search("|<|{From:,Content-Type:}|w",ADVANCE+ERRBREAK+NORESTORE) if(match_item == 2) { Call("SkipMultipart") } else { Call("ExtractAddress") } } // Sort e-mail addresses and remove duplicates. File_Open("|@(80)") // Open or switch to "output" file if(File_Size == 0) { Return } Sort(0,File_Size) //Sort entire file BOF repeat(ALL) { //Search & delete duplicate lines Search("^{.*}\N\1$",REGEXP+MAX+ERRBREAK) Del_line() } Buf_Switch(#104) // Return to original Edit Buffer // Now Tidy up file if (#99==0x57495C44) //If WILDFILE running { File_Save } Return :ExtractAddress: #1=Cur_Pos Reg_Copy_Block(24,Cur_Pos,EOL_Pos) // copy From: to T-Reg if(Cur_Char=='"') // Display-Name in quotes { Char(1) #1=Cur_Pos Search('"',NOERR) if (!Error_Match) // found { Reg_Copy_Block(25,#1,Cur_Pos) // Copy Display-Name to T-Reg #1=Cur_Pos+1 // advance past name } } else // assume Display-Name followed by or [mailto:email] { #1=Cur_Pos Search_Block('|{<,[}',#1,EOL_Pos,NOERR) if (!Error_Match) // found { Search("|w",REVERSE+NOERR) // remove trailing spaces from name Reg_Copy_Block(25,#1,Cur_Pos) } else // assume just Display-Name on line { Reg_Copy_Block(25,#1,EOL_Pos) // Copy Display-Name to T-Reg } } // Search for email address Search_Block("[a-zA-Z0-9\_\-\.]+@[a-zA-Z0-9\_\-\.]+\.[a-zA-Z][a-zA-Z]+",#1,EOL_Pos,BEGIN+REGEXP+MAX+ADVANCE+NOERR) if (!Error_Match&&Chars_Matched>1) { Reg_Copy_Block(26,CP-Chars_Matched,CP) // Copy e-mail address to T-Reg if(Reg_Compare(26,@(25))==0) // if Display-Name == email { reg_empty(25) } } if(Reg_Size(26)==0) { Return } // no email address // Do not add the following specific e-mails. // Add as many lines as needed, customised to your needs. <============ if(Reg_Compare(26,"bill_gates@microsoft.com")==0) { Return } // Outupt Information File_Open("|@(80)") // Open or switch to "output" file End_Of_File() Reg_Ins(26) // e-mail address Ins_Char(9) Reg_Ins(25) // Display-Name // Un-comment the following to include full From: line (for debugging) // Ins_Char(9) // Reg_Ins(24) Ins_Newline(1) Buf_Switch(#104) // Return to original Edit Buffer Return //=========================================================== // This skips the body of a multipart MIME message. :SkipMultipart: #2=Cur_Pos if(Match("multipart")==0) // this is a 'multipart' message { Search("boundary",NOERR|ADVANCE) if (Error_Match) { Goto_Pos(#2) Return } // missing required parameter Search("=",ADVANCE|NOERR) // Look for boundary string if (Cur_Char=='"') { //If string in double-quotes... Char(1) Block_Begin(Cur_Pos) Search('"',ADVANCE|NOERR) Block_End(Cur_Pos-1) } else { Block_Begin(Cur_Pos) Search("|X",NOERR) Block_End(Cur_Pos) } Reg_Copy_Block(27,Block_Begin,Block_End) // save boundary string // Some Email Clients put headers in multi-part preamble Block_Begin(Cur_Pos) Search("|<--|@(27)") // skip preamble Block_End(Cur_Pos) Search_Block("|