Pers.narod.ru. Обучение. Автоматизация в OutLook - обрабатываем письма |
Заметка сделана как ответ на вопрос об автоматизированной обработке писем с помощью Visual Basic for Applications. Приводится пример такой обработки, состоящей из 2 этапов. Можно было бы и все сделать на VBA, просто код станет сложней.
Во-первых, у нас есть форма, автоматически рассылающая письма, например, как в тесте на Интернет-зависимость. Атрибуты HTML name="имя" позволяют задать имена компонентам формы, а имеющийся у большинства компонентов, по крайней мере, у текстовых полей ввода, атрибут value="значение" дает возможность передать внешней программе введенную или выбранную пользователем строку данных.
Если в заголовке формы мы указали данные вида
<form action="mailto:ВАШ@АДРЕС.ПОЧТЫ?subject=Internet-Test" method="post" enctype="text/plain" name="Q">то в письме с темой "Internet-Test" к нам придет набор строк вида "имя=значение", например, для текстового поля с тегом
<input type="text" size="2" maxlength="2" name="Vozrast" value="0">при условии, что пользователь ввел значение 30, это будет запись
Написать процедуру обработки таких файлов - не проблема, для этого подойдет почти любой язык. Например, для меня проще всего было скидать все файлы в одну папку и написать на Си или Паскале программу-"сканер", которая соберет данные из всех файлов текущей папки в единую текстовую таблицу, где одной строке соответствуют данные из одного файла, а столбцы разделены любым нужным символом, таким как табуляция или точка с запятой. После этого файл можно открыть в Excel и делать с ним что угодно.
Вот пример такого "сканера" на Borland C++ 3.1, который я использовал конкретно для теста на Интернет-зависимость:
#define MASK "*.*" // Обработка теста на Интернет-зависимость // Берет файлы с тестами по маске из первого параметра командной строки // Выход - файл test_tab.txt #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dir.h> #include <ctype.h> #define MAX_STR 128 #define CATEGORIES 17 char Text[MAX_STR][CATEGORIES]; int R[20],Q[20]; char *Columns[CATEGORIES]= { "Vozrast", "Pol", "Stag", "Status", "Family", "Children", "Education", "City", "Other", "Money", "Inet_for_work", "Specialist", "Humanitarian", "Drunkard", "Gamer", "Suicide", "tDiagnosis" }; char *ReadStr (FILE *f, char *Str) { //Чтение строки из файла char *Ptr=fgets (Str,MAX_STR,f); int l=strlen(Str)-1; while ((Str[l]=='\n') || (Str[l]=='\r')) Str[l--]='\0'; return Ptr; } int main (int argc, char *argv[]) { char s[MAX_STR], *Ptr, *Ptr2; FILE *r,*w; struct ffblk ffblk; int done,i,j,n,files=0; clrscr(); if (argc!=2) { printf ("\n Sorry, you must run me with file name or mask as parameter!" "\n Example:" "\n test_tab.exe *.txt" ); return 1; } w=fopen ("test_tab.txt","wt"); if (w==NULL) { printf ("\n Can't open the file test_tab.txt to write info :-("); return 1; } done = findfirst(argv[1],&ffblk,0); while (!done) { r=fopen (ffblk.ff_name,"rt"); if (r==NULL) printf ("\n Can't open the file %s to read info :-(",ffblk.ff_name); else if ( stricmp("test_tab.txt",ffblk.ff_name) && stricmp("test_tab.exe",ffblk.ff_name)) { for (j=0; j<CATEGORIES; j++) strcpy (&Text[j][0],""); for (j=0; j<20; j++) { Q[j]=R[j]=0; } for (i=0; ; i++) { ReadStr (r,s); if (feof(r)) break; Ptr=strchr (s,'='); if (Ptr) { *Ptr = '\0'; if (tolower(s[0])=='q') { //Найден ответ на вопрос n=atoi(&s[1]); if (n) Q[n-1]=atoi(Ptr+1); } else if (tolower(s[0])=='r') { n=atoi(&s[1]); if (n) R[n-1]=atoi(Ptr+1); } else { for (j=0; j<CATEGORIES; j++) { if (!stricmp(s,Columns[j])) { //Найден столбец категории if (j==CATEGORIES-1) { //Число очков - особая обработка Ptr++; while (!isdigit(*Ptr)) Ptr++; Ptr2=Ptr; while (isdigit(*Ptr2)) Ptr2++; *Ptr2='\0'; strcpy(&Text[CATEGORIES-1][0],Ptr); break; } else { strcpy(&Text[j][0],(Ptr+1)); break; } } } } } } //Пишем в файл fprintf (w,"%s\t",ffblk.ff_name); //Разделителями для Excel будут ТАБУЛЯЦИИ for (j=0; j<CATEGORIES-1; j++) { fprintf (w,"%s\t",&Text[j][0]); } for (j=0; j<20; j++) fprintf (w,"%d\t",Q[j]); for (j=0; j<20; j++) fprintf (w,"%d\t",R[j]); fprintf (w,"%s \n",&Text[CATEGORIES-1][0]); fclose (r); cprintf ("\r %d files",++files); } done = findnext(&ffblk); } cprintf ("\r\n OK. See TEST_TAB.TXT in current folder"); fclose (w); return 0; }
Вот соответствующий файл на C++ и исполняемый файл в архиве: test_tab.zip, 14 Кб.
Единственное "узкое место" в нашей несложной технологии - необходимость вручную сохранять каждое письмо, да еще и всё в одну папку. Когда этих писем несколько тысяч, как и бывает в жизни, говорить об автоматизации теряет смысл.
К счастью, при установленном приложении Outlook из Microsoft Office (нужен именно настроенный Outlook, а не клиент Outlook Express, поставляемый с Internet Explorer), решить проблему нетрудно. В сущности, мы хотим сделать следующее:
Вот соответствующий код на Visual Basic for Applications (VBA):
Dim myOutlookApp As Object Dim myOutlookNameSpace As Object Public Function StartOutlook() As Boolean On Error GoTo CannotInitialize StartOutlook = True Set myOutlookApp = CreateObject("Outlook.Application") Set myOutlookNameSpace = myOutlookApp.GetNameSpace("MAPI") Done: Exit Function CannotInitialize: StartOutlook = False Resume Done End Function Public Sub CombineMessagesByTopic(Subject As String) Dim f As Object Dim m As Object Dim buf As String Dim fn As Integer Dim atc As Outlook.Attachment Dim Counter As Integer If myOutlookApp Is Nothing Then If StartOutlook = False Then MsgBox "Ошибка при открытии приложения Outlook" Exit Sub End If End If Set f = myOutlookNameSpace.GetDefaultFolder(olFolderInbox) Counter = 0 For Each m In f.Items buf = "" ' здесь я сначала пытался извлечь вложения из файла 5 мегабайт. ' Скрипт извлек 220 штук и перестал работать от нехватки ресурсов :-) ' Поэтому ниже письма обрабатываются по 160 штук 'For Each atc In m.Attachments ' If atc.Type = 5 Then ' Set fs = CreateObject("Scripting.FileSystemObject") ' atc.SaveAsFile (fs.GetTempName) ' End If 'Next If InStr(m.Subject, Subject) > 0 Then buf = buf & vbCrLf & m.Body 'm.UnRead = False 'если раскомментарить строку выше - будем помечать письмо как прочитанное m.Delete 'удаляем обработанное письмо Counter = Counter + 1 End If If Len(buf) > 0 Then Set fs = CreateObject("Scripting.FileSystemObject") Set a = fs.CreateTextFile(fs.GetTempName, True) a.WriteLine (buf) a.Close If Counter > 159 Then MsgBox "160 писем сохранено и удалено. Запустите еще раз для след. порции" Exit Sub End If End If Next MsgBox "Все письма сохранены и удалены" End Sub Private Sub CommandButton1_Click() 'Вызывается по нажатию первой кнопки в документе Dim Subject As String Dim OutputFile As String Subject = "Internet-Test" Call CombineMessagesByTopic(Subject) End Sub
Чтобы не думать, куда и как вставить этот код, вот архив с готовым файлом Word, содержащим единственную кнопку "Нажми меня": outlook_letter_collection.zip, 12 Кб
Разобраться, как изменить или дописать этот код, думаю, Вы сможете сами. Для работы с компонентами форм в Word есть панель инструментов "Элементы управления". Достаточно ее включить, нажать на ней первую кнопку "Констуктор", а затем сделать двойной щелчок на изменяемом объекте. Отжав кнопку "Констуктор", мы вернемся в обычный режим работы.
Этот или подобный файл будет работать при следующих условиях:
На выходе программы - документ test_tab.txt, пригодный для чтения Excel'ем.
См. также: материалы по VBA и С++ в разделе "Обучение"
гостевая; E-mail |