G.12. utl_smtp — отправка электронных писем по протоколу SMTP #
utl_smtp — это расширение Postgres Pro, предназначенное для отправки электронных писем по протоколу SMTP из PL/pgSQL. Функциональность, предоставляемая этим модулем, во многом пересекается с функциональностью пакета UTL_SMTP в Oracle.
G.12.1. Установка #
Расширение utl_smtp поставляется вместе с Postgres Pro Enterprise в отдельном пакете pgpro-orautl-ent-18 (подробные инструкции по установке приведены в Главе 17). Чтобы включить utl_smtp, создайте расширение с помощью следующего запроса:
CREATE EXTENSION utl_smtp;
G.12.2. Использование #
Чтобы отправить электронное письмо с помощью расширения utl_smtp, необходимо вызывать функции в определённом порядке:
Сначала откройте соединение, вызвав функцию
open_connection.Затем отправьте команду
HELO/EHLOSMTP-серверу, используя функцииhelo/ehloсоответственно.Отправьте адреса отправителя и получателя, используя функции
mailиrcpt.Вызовите функцию
opendata, чтобы начать процесс отправки данных посредством отправки командыDATASMTP-серверу.После этого можно многократно вызывать функции
write_dataиwrite_raw_dataдля отправки фактических данных.Процесс отправки данных завершается вызовом функции
close_data.После вызова
open_dataможно вызывать только следующие функции:write_data,write_raw_dataилиclose_data. Вызов других функций приведёт к возникновению ошибки.Кроме того, процесс отправки данных можно упростить, однократно вызвав функцию
data.После вызова
close_dataилиdataэлектронное письмо отправлено — вызовите функциюquit, чтобы завершить соединение.
G.12.3. Типы данных #
Расширение utl_smtp предоставляет следующие типы данных:
Тип
replyпредставляет собой строку ответа SMTP. Каждая строка ответа SMTP состоит из кода ответа, за которым следует текстовое сообщение. Для большинства команд SMTP ожидается одна строка ответа, для некоторых — несколько строк.Таблица G.101. Параметры
replyПараметр Описание code3-значный код ответа textТекстовое сообщение ответа Тип
connectionпредставляет собой соединение по протоколу SMTP.Таблица G.102. Параметры
connectionПараметр Описание hostИмя или IP-адрес удалённого узла при установке соединения. portНомер порта подключённого удалённого SMTP-сервера. tx_timeoutВремя ожидания расширением utl_smtp операций чтения или записи в этом соединении, в секундах. Таймаут соединения с сервером всегда составляет 60 секунд и не может быть настроен. private_socketЭтот параметр используется внутри Postgres Pro и не должен изменяться вручную.
G.12.4. Функции utl_smtp #
Расширение utl_smtp предоставляет функции для отправки электронных писем по протоколу SMTP. Обратите внимание, что функции, которые должны возвращать несколько строк ответа, возвращают массив типа reply.
-
auth(#cconnection,usernametext,passwordtext,schemestextdefault 'PLAIN') returnsreply Отправляет SMTP-серверу команду
AUTHдля аутентификации. В настоящее время поддерживается только схема аутентификацииPLAIN.-
close_all_connections() returns#void Закрывает все SMTP-соединения и освобождает все связанные с ними ресурсы.
-
close_connection(#cconnection) returnsvoid Закрывает указанное SMTP-соединение. Эту функцию можно вызвать при отправке данных на сервер перед вызовом
close_data. В этом случае следующий вызов функции с этим соединением выдаст исключение.-
close_data(#cconnection) returnsreply Завершает сообщение электронной почты отправкой последовательности
<CR><LF>.<CR><LF>(одна точка в начале строки).-
command(#cconnection,cmdtext,argtextdefault null) returnsreply Отправляет произвольную команду SMTP и может возвращать одну строку ответа.
-
command_replies(#cconnection,cmdtext,argtextdefault null) returnsreply[] Отправляет произвольную команду SMTP и может возвращать несколько строк ответа.
-
data(#cconnection,bodytext) returnsreply Указывает тело электронного письма. По сути, это последовательность вызовов следующих функций:
open_data,write_dataиclose_data.-
ehlo(#cconnection,domaintext) returnsreply Выполняет начальное согласование с SMTP-сервером с помощью команды
EHLO. Сервер возвращает часть своей конфигурации.-
helo(#cconnection,domaintext) returnsreply Выполняет начальное согласование с SMTP-сервером с помощью команды
HELO.-
help(#cconnection,commandtextdefault null) returnsreply Отправляет команду
HELP. Эта команда может быть реализована не на всех SMTP-серверах.-
last_reply(#cconnection) returnsreply Возвращает последний ответ SMTP-сервера.
-
mail(#cconnection,sendertext,parameterstextdefault null) returnsreply Инициирует транзакцию отправки электронного письма с сервером, отправляя команду
MAILс адресом отправителя.-
noop(#cconnection) returnsreply Выдаёт команду
NOOP. Эта функция в основном используется для проверки соединения.-
open_connection(#hosttext,portintdefault 25,tx_timeoutintdefault null,secure_connection_before_smtpbooldefault false,verify_peerbooldefault true) returnsconnection Открывает соединение с SMTP-сервером. Параметр
secure_connection_before_smtpуказывает, устанавливается ли подключение TLS до соединения SMTP (по сути, если этот параметр имеет значение true, соединение будет использовать SMTPS вместо SMTP). Параметрverify_peerуказывает, проверяются ли сертификаты при установке подключения TLS.-
open_data(#cconnection) returnsreply Отправляет команду
DATA, после которой можно использовать функцииwrite_dataиwrite_raw_data, чтобы написать часть электронного письма.-
quit(#cconnection) returnsreply Завершает сеанс SMTP и отключается от сервера.
-
rcpt(#cconnection,recipienttext,parameterstextdefault null) returnsreply Указывает получателя электронного письма. Транзакция отправки сообщения должна быть запущена предыдущим вызовом
MAIL, а соединение с почтовым сервером должно быть открыто и инициализировано предыдущими вызовамиopen_connectionиheloилиehloсоответственно.-
rset(#cconnection) returnsreply Завершает текущую транзакцию отправки письма. Клиент может вызвать
rsetв любое время после открытия соединения с SMTP-сервером с помощьюopen_connectionдо вызоваdataилиopen_data.-
set_reply_error_check(#cconnection,enablebool) returnsvoid Определяет поведение функции. Если для параметра
enableустановлено значение true (по умолчанию), любая ошибка на SMTP-сервере выдаёт исключение. Если установлено значение false, для определения ошибки пользователю следует самостоятельно анализировать результаты, возвращаемые функциями.-
starttls(#cconnection,verify_peerbooldefault true) returnsreply Отправляет команду
STARTTLSдля защиты SMTP-соединения с использованием TLS.-
vrfy(#cconnection,recipienttext) returnsreply Отправляет команду
VRFYдля проверки корректности адреса получателя электронного письма. Эта команда может быть реализована не на всех SMTP-серверах и может возвращать некорректную информацию, поэтому не рекомендуется её использовать.-
write_data(#cconnection,datatext) returnsvoid Отправляет часть текста сообщения, включая заголовки, SMTP-серверу. При повторном вызове
write_dataдобавляет данные к сообщению.-
write_raw_data(#cconnection,datatext) returnsvoid Отправляет часть текста сообщения, включая заголовки, SMTP-серверу. При повторном вызове
write_dataдобавляет данные к сообщению. Эта функция аналогична функцииwrite_data.
G.12.5. Примеры #
В следующем примере показана отправка электронного письма без вложения с помощью utl_smtp.
DO $$
DECLARE
conn utl_smtp.connection;
BEGIN
conn := utl_smtp.open_connection('smtp.mail.ru', 25, 10);
perform utl_smtp.ehlo(conn, 'localhost');
perform utl_smtp.starttls(conn);
perform utl_smtp.ehlo(conn, 'localhost');
perform utl_smtp.auth(conn, 'test_email@example.com', 'super-secret-password');
perform utl_smtp.mail(conn, 'sender@example.com');
perform utl_smtp.rcpt(conn, 'recipient@example.com');
perform utl_smtp.open_data(conn);
perform utl_smtp.write_data(conn, E'Content-Type: multipart/mixed; boundary=------------------------6f48b7d5ded0c5fc\n');
perform utl_smtp.write_data(conn, E'Mime-Version: 1.0\n');
perform utl_smtp.write_data(conn, E'From: Sender <sender@example.com>\n');
perform utl_smtp.write_data(conn, E'To: Recipient <recipient@example.com>\n');
perform utl_smtp.write_data(conn, E'Subject: mail from utl_smtp\n');
perform utl_smtp.write_data(conn, E'--------------------------6f48b7d5ded0c5fc\n');
perform utl_smtp.write_data(conn, E'Content-Type: text/plain; charset=\"UTF-8\"\n');
perform utl_smtp.write_data(conn, E'Content-Transfer-Encoding: 8bit\n\n');
perform utl_smtp.write_data(conn, E'This is body from inside Postgres Pro\n');
perform utl_smtp.write_data(conn, E'Sent using utl_smtp\n');
perform utl_smtp.write_data(conn, E'\n--------------------------6f48b7d5ded0c5fc--\n');
perform utl_smtp.close_data(conn);
perform utl_smtp.quit(conn);
END$$;В следующем примере показана обработка исключений с помощью utl_smtp.
DO $$
DECLARE
...
r utl_smtp.reply;
BEGIN
...
some utl_smtp funcion calls
...
exception
when others then
r = utl_smtp.last_reply(conn);
if r.code >= 500 then
raise notice 'caught permanent error';
elsif r.code >= 400 then
raise notice 'caught transient error';
else
raise notice 'some other error';
end if;
END$$;G.12. utl_smtp — send emails over SMTP #
utl_smtp is a Postgres Pro extension designed for sending emails over SMTP from PL/pgSQL. The functionality provided by this module overlaps substantially with the functionality of Oracle's UTL_SMTP package.
G.12.1. Installation #
The utl_smtp extension is provided with Postgres Pro Enterprise in a separate pre-built package pgpro-orautl-ent-18 (for the detailed installation instructions, see Chapter 17). To enable utl_smtp, create the extension using the following query:
CREATE EXTENSION utl_smtp;
G.12.2. Usage #
To send an email using utl_smtp, the functions must be called in a specific order:
First, open connection by calling the
open_connectionfunction.Then send
HELO/EHLOcommand to the SMTP server usinghelo/ehlorespectively.Send sender and recipient addresses using
mailandrcptfunctions.Call the
open_datafunction to start data sending process by sending theDATAcommand to the SMTP server.After that,
write_dataandwrite_raw_datacan be called repeatedly to send the actual data.The data sending process is terminated by calling
close_data.Once
open_datais called, the only functions that can be called arewrite_data,write_raw_data, orclose_data. Other calls result in an error being raised.Alternatively, data sending process can be streamlined with one call of
data.After calling
close_dataordata, the email is sent — callquitto end the connection.
G.12.3. Data Types #
The utl_smtp extension provides the following data types:
The
replytype is used to represent an SMTP reply line. Each SMTP reply line consists of a reply code followed by a text message. While a single reply line is expected for most SMTP commands, some SMTP commands expect multiple reply lines.Table G.101.
replyParametersParameter Description code3-digit reply code textText message of the reply The
connectiontype represents an SMTP connection.Table G.102.
connectionParametersParameter Description hostName or IP address of the remote host when connection is established. portPort number of the remote SMTP server connected. tx_timeoutTime in seconds that utl_smtp waits before timing out in a read or write operation in this connection. The timeout of server connection is always 60 seconds and cannot be configured. private_socketThis parameter is used internally by Postgres Pro and should not be modified manually.
G.12.4. utl_smtp Functions #
utl_smtp provides functions for sending emails over SMTP. Note that the functions that are supposed to return multiple reply lines return the reply array.
-
auth(#cconnection,usernametext,passwordtext,schemestextdefault 'PLAIN') returnsreply Sends the
AUTHcommand to authenticate to the SMTP server. Currently only thePLAINauthentication scheme is supported.-
close_all_connections() returns#void Closes all SMTP connections and releases all associated resources.
-
close_connection(#cconnection) returnsvoid Closes the specified SMTP connection. This function can be called when sending data to the server before
close_data. In this case, the next call to a function with this connection will raise an exception.-
close_data(#cconnection) returnsreply Ends the e-mail message by sending the sequence
<CR><LF>.<CR><LF>(a single period at the beginning of the line).-
command(#cconnection,cmdtext,argtextdefault null) returnsreply Sends an arbitrary SMTP command and can return a single reply line.
-
command_replies(#cconnection,cmdtext,argtextdefault null) returnsreply[] Sends an arbitrary SMTP command and can return multiple reply lines.
-
data(#cconnection,bodytext) returnsreply Specifies the body of an email. It is essentially a sequence of calls:
open_data,write_data, andclose_data.-
ehlo(#cconnection,domaintext) returnsreply Performs the initial handshake with SMTP server using the
EHLOcommand. The server returns a part of its configuration.-
helo(#cconnection,domaintext) returnsreply Performs the initial handshake with SMTP server using the
HELOcommand.-
help(#cconnection,commandtextdefault null) returnsreply Sends the
HELPcommand. This command might not be implemented on all SMTP servers.-
last_reply(#cconnection) returnsreply Returns the last reply of the SMTP server.
-
mail(#cconnection,sendertext,parameterstextdefault null) returnsreply Initiates an email transaction with the server by sending the
MAILcommand with the sender address.-
noop(#cconnection) returnsreply Issues the
NOOPcommand. This function is mainly used to check the connection.-
open_connection(#hosttext,portintdefault 25,tx_timeoutintdefault null,secure_connection_before_smtpbooldefault false,verify_peerbooldefault true) returnsconnection Opens a connection to an SMTP server. The
secure_connection_before_smtpparameter specifies if the TLS connection is established before the SMTP connection (essentially, if this parameter is true, the connection will be using SMTPS instead of SMTP). Theverify_peerparameter specifies if the certificates are validated when establishing the TLS connection.-
open_data(#cconnection) returnsreply Sends the
DATAcommand after which you can usewrite_dataandwrite_raw_datato write a portion of the email.-
quit(#cconnection) returnsreply Terminates an SMTP session and disconnects from the server.
-
rcpt(#cconnection,recipienttext,parameterstextdefault null) returnsreply Specifies the recipient of an email. The message transaction must have been started by a prior call to
MAIL, and the connection to the mail server must have been opened and initialized by prior calls toopen_connectionandheloorehlorespectively.-
rset(#cconnection) returnsreply Terminates the current mail transaction. The client can call
rsetat any time after the connection to the SMTP server has been opened by means ofopen_connectionuntildataoropen_datais called.-
set_reply_error_check(#cconnection,enablebool) returnsvoid Determines function behavior. If the
enableparameter is set to true, which is the default, any error on the SMTP server raises an exception. If it is set to false, the user is responsible for analyzing the results returned by the functions to determine the error.-
starttls(#cconnection,verify_peerbooldefault true) returnsreply Sends the
STARTTLScommand to secure the SMTP connection using TLS.-
vrfy(#cconnection,recipienttext) returnsreply Sends the
VRFYcommand to verify the validity of the destination email. This command might not be implemented on all SMTP servers, and it may not return the correct information so it is not recommended to use it.-
write_data(#cconnection,datatext) returnsvoid Sends a portion of the text of the message, including headers, to the SMTP server. A repeated call to
write_dataappends data to the message.-
write_raw_data(#cconnection,datatext) returnsvoid Sends a portion of the text of the message, including headers, to the SMTP server. A repeated call to
write_dataappends data to the message. The same aswrite_data.
G.12.5. Examples #
The following example demonstrates sending an email without attachment using utl_smtp.
DO $$
DECLARE
conn utl_smtp.connection;
BEGIN
conn := utl_smtp.open_connection('smtp.mail.ru', 25, 10);
perform utl_smtp.ehlo(conn, 'localhost');
perform utl_smtp.starttls(conn);
perform utl_smtp.ehlo(conn, 'localhost');
perform utl_smtp.auth(conn, 'test_email@example.com', 'super-secret-password');
perform utl_smtp.mail(conn, 'sender@example.com');
perform utl_smtp.rcpt(conn, 'recipient@example.com');
perform utl_smtp.open_data(conn);
perform utl_smtp.write_data(conn, E'Content-Type: multipart/mixed; boundary=------------------------6f48b7d5ded0c5fc\n');
perform utl_smtp.write_data(conn, E'Mime-Version: 1.0\n');
perform utl_smtp.write_data(conn, E'From: Sender <sender@example.com>\n');
perform utl_smtp.write_data(conn, E'To: Recipient <recipient@example.com>\n');
perform utl_smtp.write_data(conn, E'Subject: mail from utl_smtp\n');
perform utl_smtp.write_data(conn, E'--------------------------6f48b7d5ded0c5fc\n');
perform utl_smtp.write_data(conn, E'Content-Type: text/plain; charset=\"UTF-8\"\n');
perform utl_smtp.write_data(conn, E'Content-Transfer-Encoding: 8bit\n\n');
perform utl_smtp.write_data(conn, E'This is body from inside Postgres Pro\n');
perform utl_smtp.write_data(conn, E'Sent using utl_smtp\n');
perform utl_smtp.write_data(conn, E'\n--------------------------6f48b7d5ded0c5fc--\n');
perform utl_smtp.close_data(conn);
perform utl_smtp.quit(conn);
END$$;
The following example demonstrates exception handling with utl_smtp.
DO $$
DECLARE
...
r utl_smtp.reply;
BEGIN
...
some utl_smtp funcion calls
...
exception
when others then
r = utl_smtp.last_reply(conn);
if r.code >= 500 then
raise notice 'caught permanent error';
elsif r.code >= 400 then
raise notice 'caught transient error';
else
raise notice 'some other error';
end if;
END$$;