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, это будет запись
Vozrast=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 есть панель инструментов "Элементы управления". Достаточно ее включить, нажать на ней первую кнопку "Констуктор", а затем сделать двойной щелчок на изменяемом объекте. Отжав кнопку "Констуктор", мы вернемся в обычный режим работы.

Этот или подобный файл будет работать при следующих условиях:

  1. Должен быть установлен Microsoft Outlook (а не Outlook Express), и письма с тестами залиты во "Входящие". Поддержка VBA (Бейсика) тоже должна быть. Все это есть с гарантией, если ставить компоненты офиса полностью.
  2. Если на открытии документа было окно "Отключить макросы?" и мы нажали "Да" - зайти в меню Сервис, Параметры, вкладка Безопасность, кнопка "Защита от макросов", выбрать "Средняя" и "ОК" При новом открытии документа не отключать макросы.
  3. Если есть Касперский с включенным Office Guard - попытаться истребить Office Guard. Альтернатива - отвечать "Да" на запросы о запуске приложений и создании файлов - но тогда запросов будет столько же, сколько обработано писем. Файлы могут оказаться в папке "Мои документы" текущего пользователя или же в текущей папке документа - уже не помню, от чего это зависит.
  4. После завершения, файлы *.tmp пригодны для дальнейшей обработки программой test_tab, например, запущенной в виде:
    test_tab.exe *.tmp
    (макрос сохраняет файлы с расширением *.tmp)

На выходе программы - документ test_tab.txt, пригодный для чтения Excel'ем.

См. также: материалы по VBA и С++ в разделе "Обучение"

Рейтинг@Mail.ru
вверх гостевая; E-mail
Hosted by uCoz