ShS's Blog

Just another sysadmin's weblog

Скрипт для отправки сообщения по e-mail, с использованием протокола SMTP

Posted by shs на 2009/12/11

В скрипте, опубликованном ранее, имеется функция отправки сообщения по e-mail. В этом посте хочу остановиться на отправке e-mail при помощи скрипта чуть-чуть подробнее.

Простейшая функция отправки сообщения, использующая  доступный для нас smtp-сервер будет выглядеть следующим образом:

////////////////////////////////////////////////////////////////////////////
// JScript  shs smtp_send_mail.js
//Этот скрипт предназначен для отправки e-mail с компьютера,
//на котором не установлен локальный SMTP-сервис/сервер
///////////////////////////////////////////////////////////////////////////
objEmail = WScript.CreateObject("CDO.Message");  //создаем объект CDO.Message
//
//Зададим значения для полей письма.
objEmail.From = "sender@dandelion.ru";  	//адрес отправителя
objEmail.To = "recipient@sunflower.ru"; 		//адрес получателя
objEmail.Subject = "This’s the test email"; 	//тема
objEmail.Textbody = "You may delete this mail";  //тело письма
//
//Зададим значения для полей конфигурации
with (objEmail.Configuration.Fields) {
	Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2; //посылать сообщения по сети, используя SMTP
	Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mailserver"; //ip или DNS-имя smtp-сервера
	Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25; // порт smtp-сервера, на котором он принимает сообщения
	Update();
}
try {
	objEmail.Send();
}
catch(e) {
	WScript.Echo(e.number);
	WScript.Echo(e.message);
}

Для отправки сообщения мы используем объект COM-объекты Collaboration Data Objects (CDO):

 

Скрипт очень простой, т.к. выполняет очень простые действия: отправляет письмо на английском языке, используя smtp-сервер (без авторизации на  оном smtp-сервере). Зачастую, для выполнения простых административных задач (например, отправки каких-либо alert’ов) этого бывает достаточно. А что, если же нам захочется большего? Давайте попробуем усовершенствовать скрипт.

А что, если smtp-сервер требует аутентификацию (например, если в качестве smtp-сервера мы захотим использовать smtp.mail.ru, то мы не сможем это сделать без предварительной аутентификации)? Давайте попробуем аутентифицироваться, для этого нам потребуется добавить всего 3 строчки внутрь блока with{…}, для изменения объекта конфигурации, после чего этот блок кода примет следующий вид (добавленные строки отображаются на темном фоне):

with (objEmail.Configuration.Fields) {
	Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2; //посылать сообщения по сети (используя SMTP)
	Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mailserver"; //ip или DNS-имя smtp-сервера
	Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25; // порт smtp-сервера
	Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1; // используем basic authentication
	Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = "username"; //имя пользователя
	Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "userpassword"; //пароль пользователя
	Update();
}

Пойдем дальше. Если мы попробуем отправить письмо, содержащие кириллицу…

objEmail.Subject = "это тестовое письмо";
objEmail.Textbody = "это тестовое письмо, его можно удалить";

…, то на принимающей стороне получим нечитабельную тарабарщину, т.к. по умолчанию текстовые части письма должны содержать простой текст в кодировке  US-ASCII. Чтобы исправить положение, мы должны указать кодировку письма. Так, для передачи сообщений на русском языке, мы должны выбрать одну из следующих кодировок: «windows-1251», «koi8-r», «utf-7» или «utf-8», что мы и сделаем, задав значение поля Charset:

objEmail.BodyPart.CharSet = "utf-8";

Ну, и наконец, если нам потребуется добавить к e-mail какие-либо файлы, в качестве вложений, то для этого используем метод AddAttachment, например, так:

objEmail.AddAttachment("c:\\nagent_log.txt");

В результате, получим такой скрипт:

////////////////////////////////////////////////////////////////////////////
// JScript  shs smtp_send_mail.js
//Этот скрипт предназначен для отправки e-mail с компьютера,
//на котором не установлен локальный SMTP-сервис/сервер
///////////////////////////////////////////////////////////////////////////
objEmail = WScript.CreateObject("CDO.Message");  //создаем объект CDO.Message
//
//Зададим значения для полей письма.
objEmail.From = "sender@dandelion.ru";  	//адрес отправителя
objEmail.To = "recipient@sunflower.ru"; 		//адрес получателя
objEmail.BodyPart.CharSet = "utf-8";               //задаем кодовую страницу сообщения
objEmail.Subject = "это тестовое письмо"; 	//тема письма
objEmail.Textbody = "это тестовое письмо, его можно удалить";  //тело письма
objEmail.AddAttachment("c:\\nagent_log.txt");	//добавляем к письму вложение: файл c:\nagent_log.txt
//
//Зададим значения для полей конфигурации
with (objEmail.Configuration.Fields) {
	Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2; //посылать сообщения по сети, используя SMTP
	Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mailserver"; //ip или DNS-имя smtp-сервера
	Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25; // порт smtp-сервера
	Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1; // используем basic authentication
	Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = "username"; //имя пользователя
	Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "userpassword";  //пароль пользователя
	Update();
}
try {
	objEmail.Send();
}
catch(e) {
	WScript.Echo(e.number);  //выводим номер ошибки
	WScript.Echo(e.message); //выводим соощение об ошибке
}

PS Во время работы со скриптом столкнулся с тем, что он без проблем работал с почтовым сервером, находящимся внутри локальной сети, но никак не хотел работать с внешними smtp-серверами (smtp.mail.ru, smtp.yandex.ru и т.п.). Скрипт выдавал ошибку с номером -2147220973 (если перевести в hex, то получим 0x80040213). Погуглив, обнаружил, что такая ошибка по-английски звучит, как «The transport failed to connect to the server» и возникает, зачастую, как и в моем случае, по непонятным причинам.
Я «стопятьсот» раз перепроверил скрипт и настройки компьютера и знал, что нигде не ошибся: имя smtp-сервера, имя пользователя и пароль были указаны правильно, никакой файервол не перекрывает доступ во внешний мир, но скрипт упорно вываливался с этой ошибкой. Тогда я попробовал запустить его на проблемной машине от имени другой учетной записи с правами локального администратора – скрипт отработал без ошибок! Я уже было решил, что где-то перестарался и слишком сильно «завинтил гайки» с SRP и NTFS permissions, но в логах ничего подозрительного не обнаружил. Тогда я выдал учетной записи, под которой запускал скрипт, права локального администратора, но это не возымело никакого эффекта – скрипт, по-прежнему, завершался аварийно с ошибкой 0x80040213! Стало понятно, что проблема — в профиле пользователя.
Дальнейший «разбор полетов» не производил и просто убил проблемный профиль пользователя. После этого скрипт стал работать, как положено, и больше не выдавал сообщений о мифической невозможности соединиться с smtp-сервером.

Реклама

комментариев 20 to “Скрипт для отправки сообщения по e-mail, с использованием протокола SMTP”

  1. […] Комментарии (RSS) « Скрипт для отправки сообщения по e-mail, с использованием… […]

  2. pk said

    День добрый.
    Парюсь с этим скриптом — никак не могу заставить его работать. Если отправлять файл из корневого каталога, то все нормально. А если в путь добавляется хоть один каталог, то начинает вываливаться ошибка «Синтаксическая ошибка в имени файла, имени папки или метке тома» (строка 14, символ 1).
    Не подскажете в чем может быть дело?

    ////////////////////////////////////////////////////////////////////////////
    // JScript shs smtp_send_mail.js
    //Этот скрипт предназначен для отправки e-mail с компьютера,
    //на котором не установлен локальный SMTP-сервис/сервер
    ///////////////////////////////////////////////////////////////////////////
    objEmail = WScript.CreateObject(«CDO.Message»); //создаем объект CDO.Message
    //
    //Зададим значения для полей письма.
    objEmail.From = «pk@domen.ru»; //адрес отправителя
    objEmail.To = «pk@domen.ru»; //адрес получателя
    objEmail.BodyPart.CharSet = «utf-8»; //задаем кодовую страницу сообщения
    objEmail.Subject = «это тестовое письмо»; //тема письма
    objEmail.Textbody = «это тестовое письмо, его можно удалить»; //тело письма
    objEmail.AddAttachment(«d:\\ftp\komplekt\test.txt»); //добавляем к письму вложение
    //
    //Зададим значения для полей конфигурации
    with (objEmail.Configuration.Fields) {
    Item(«http://schemas.microsoft.com/cdo/configuration/sendusing») = 2; //посылать сообщения по сети, используя SMTP
    Item(«http://schemas.microsoft.com/cdo/configuration/smtpserver») = «mail.domen.ru»; //ip или DNS-имя smtp-сервера
    Item(«http://schemas.microsoft.com/cdo/configuration/smtpserverport») = 25; // порт smtp-сервера

    Update();
    }
    try {
    objEmail.Send();
    }
    catch(e) {
    WScript.Echo(e.number); //выводим номер ошибки
    WScript.Echo(e.message); //выводим соощение об ошибке
    }

  3. shs said

    2 PK:
    это от того, что у вас в 14 строке написано d:\\ftp\komplekt\test.txt,
    а должно быть d:\\ftp\\komplekt\\test.txt
    это же бубль гум JScript и в нем символ «\» является служебным, а, значит, его необходимо esc’ить, причем esc’ится он при помощи самого себя. Поэтому, если вы хотите, чтобы в вашей строке присутствовал символ «\», то его надо писать два раза подряд: «\\».

  4. pk said

    Понял. Большое спасибо!
    Буду разбираться дальше и усложнять задачу.

  5. Mary said

    подскажите, какую строчку необходимо добавить, чтобы приходило уведомление о прочтении письма на конкретный ящик

    • shs said

      Не знаю (у меня никогда не возникало подобной задачи). Думаю, если это принципиально возможно, то, пройдясь по ссылкам из моего поста, вы найдете ответ на свой вопрос.

  6. Ivan said

    Добрый день!

    Подскажите, пожалуйста, есть ли возможность отправляя письма с помощью CDO автоматически указывать адрес отправителя? Например исходя из windows авторизации…
    Чтобы письмо подписывалось адресом отправителя outlook.

    Спасибо,
    Иван

    • shs said

      Возможность есть, только CDO, тут, наверное, не поможет Думаю, что вам надо так модифицировасть скрипт, чтобы он
      1)определял дефолтный почтовый клиент
      2)определял дефолтную учетную запись в клиенте
      3)определял почтовый адрес дефолтной учетной записи

  7. Zak said

    Подскажите на примере как добавить отчет о прочтении (на VBS всё работает на js не получается)

  8. Zak said

    .VBS

    Set objEmail = CreateObject("CDO.Message")

    Const SMTP_SERVER = "10.3.64.15"
    Const CDO_SUCCESS = 4
    Const CDO_FAIL = 2
    Const CDO_DELAY = 8
    Const CDO_SUCCESS_FAIL_DELAY = 14

    objEmail.Configuration.Fields.Item _
    ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
    objEmail.Configuration.Fields.Item _
    ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = SMTP_SERVER
    objEmail.Configuration.Fields.Item _
    ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
    objEmail.Configuration.Fields.Update

    with objEmail
    .From = "support@mydomen"
    .To = "relay@todomen"
    .Subject = "A Test"
    .Textbody = "A test script"
    .Fields("urn:schemas:mailheader:return-receipt-to") = "support@mydomen"
    .DSNOptions = CDO_SUCCESS_FAIL_DELAY
    .Fields.update
    .Send
    end with

    .js

    function SendEmail(MailServer, FromUser, ToUser, Subject, Msg, Attachment)
    { try {
    var iMsg = new ActiveXObject("CDO.Message");
    iMsg.To = ToUser;
    iMsg.From = FromUser;
    iMsg.Subject = Subject;

    if (typeof(Msg)!="undefined") iMsg.TextBody = Msg
    else iMsg.TextBody = "";
    iMsg.Configuration.fields("http://schemas.microsoft.com/cdo/configuration/sendusing")=3;
    iMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver")=MailServer;
    iMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 60;
    iMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/languagecode") = 1049;
    iMsg.Configuration.Fields("urn:schemas:mailheader:disposition-notification-to") = "support@mydomen";
    iMsg.Configuration.Fields("urn:schemas:mailheader:return-receipt-to") = "support@mydomen";

    iMsg.Configuration.Fields.Update();
    iMsg.BodyPart.ContentTransferEncoding="quoted-printable";
    if (typeof(Attachment)!="undefined")
    if (Attachment!="")
    iMsg.AddAttachment(Attachment);
    iMsg.Send();
    }catch(e){ WScript.Quit(1);
    }
    }
    SendEmail("10.3.64.15","support@mydomen", "relay@todomen","A test","A test msg","");

    В js в заголовке письма нет признака

    • shs said

      не вижу в вашем JScript скрипте кода, который бы выполнял действия соответствующие следующему куску кода на VBScript:
      with objEmail
      .From = «support@mydomen»
      .To = «relay@todomen»
      .Subject = «A Test»
      .Textbody = «A test script»
      .Fields(«urn:schemas:mailheader:return-receipt-to») = «support@mydomen»
      .DSNOptions = CDO_SUCCESS_FAIL_DELAY
      .Fields.update
      .Send
      end with

      Именно присваетвается значение для DSNOptions (http://msdn.microsoft.com/en-us/library/aa487623(EXCHG.65).aspx) Delivery Status Notification (DSN) options for the message

      Добавьте в код на JScript аналогичную(ые) строку(и) и будет вам счастье:
      iMsg.DSNOptions = 14;

      • shs said

        Да, естественно, и такую строчку надо будет добавить
        iMsg.Fields(«urn:schemas:mailheader:return-receipt-to») = «support@mydomen»
        чтобы принимающая сторона знала, куда направлять уведомление

  9. Zak said

    VBS Отправитель получает и уведомление о прочтении и о доставке

    Set objEmail = CreateObject("CDO.Message")

    Const SMTP_SERVER = "10.3.64.15"
    Const From_m = "support@fromdomen"
    Const To_m = "relay@todomen"

    objEmail.Configuration.Fields.Item _
    ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
    objEmail.Configuration.Fields.Item _
    ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = SMTP_SERVER
    objEmail.Configuration.Fields.Item _
    ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
    objEmail.Configuration.Fields.Update

    with objEmail
    .From = From_m
    .To = To_m
    .Subject = "A Test"
    .Textbody = "A test script"
    .Fields("urn:schemas:mailheader:return-receipt-to") = From_m
    .DSNOptions = 14
    .Fields.update
    .Send
    end with

    Js Отправитель получает только уведомление о доставке (о прочтении нет)

    { try {
    var iMsg = new ActiveXObject("CDO.Message");

    iMsg.From = "support@fromdomen";
    iMsg.To = "relay@todomen";
    iMsg.Subject = "A test";
    iMsg.TextBody = "A test body";
    iMsg.Fields("urn:schemas:mailheader:return-receipt-to") = "suppoert@fromdomen";
    iMsg.DSNOptions = 14;

    iMsg.Configuration.fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2;
    iMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "10.3.64.15";
    iMsg.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25;
    iMsg.Configuration.Fields.Update();

    iMsg.Send();
    }catch(e){ WScript.Quit(1);
    }}

  10. Zak said

    Спасибо всем заработало (забыл iMsg.Fields.update();)

  11. Start_user said

    Подскажите, пожалуйста, что надо добавить в этот код на VBS, чтобы, при отсутствии активного подключения к Internet, Windows НЕ показывал ошибку, а просто закрывал программу?

    Const EmailFrom = «mail»
    Const EmailPassword = «***»
    Const strSmtpServer = «smtp»
    Const EmailTo = «mail»
    Set objEmail = CreateObject(«CDO.Message»)

    objEmail.From = EmailFrom
    objEmail.To = EmailTo
    objEmail.Subject = «***»
    objEmail.Textbody = «***»
    objEmail.Configuration.Fields.Item («http://schemas.microsoft.com/cdo/configuration/sendusing») = 2
    objEmail.Configuration.Fields.Item («http://schemas.microsoft.com/cdo/configuration/smtpauthenticate») = 1
    objEmail.Configuration.Fields.Item («http://schemas.microsoft.com/cdo/configuration/sendusername») = EmailFrom
    objEmail.Configuration.Fields.Item («http://schemas.microsoft.com/cdo/configuration/sendpassword») = EmailPassword
    objEmail.Configuration.Fields.Item («http://schemas.microsoft.com/cdo/configuration/smtpserver») = strSmtpServer
    objEmail.Configuration.Fields.Item («http://schemas.microsoft.com/cdo/configuration/smtpserverport») = 25
    objEmail.Configuration.Fields.Update
    objEmail.Send
    WScript.Quit

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

 
%d такие блоггеры, как: