|
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 и С++ в разделе "Обучение"
|
|