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/EHLO SMTP-серверу, используя функции helo/ehlo соответственно.

  • Отправьте адреса отправителя и получателя, используя функции mail и rcpt.

  • Вызовите функцию opendata, чтобы начать процесс отправки данных посредством отправки команды DATA SMTP-серверу.

  • После этого можно многократно вызывать функции 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(c connection, username text, password text, schemes text default 'PLAIN') returns reply #

Отправляет SMTP-серверу команду AUTH для аутентификации. В настоящее время поддерживается только схема аутентификации PLAIN.

close_all_connections() returns void #

Закрывает все SMTP-соединения и освобождает все связанные с ними ресурсы.

close_connection(c connection) returns void #

Закрывает указанное SMTP-соединение. Эту функцию можно вызвать при отправке данных на сервер перед вызовом close_data. В этом случае следующий вызов функции с этим соединением выдаст исключение.

close_data(c connection) returns reply #

Завершает сообщение электронной почты отправкой последовательности <CR><LF>.<CR><LF> (одна точка в начале строки).

command(c connection, cmd text, arg text default null) returns reply #

Отправляет произвольную команду SMTP и может возвращать одну строку ответа.

command_replies(c connection, cmd text, arg text default null) returns reply[] #

Отправляет произвольную команду SMTP и может возвращать несколько строк ответа.

data(c connection, body text) returns reply #

Указывает тело электронного письма. По сути, это последовательность вызовов следующих функций: open_data, write_data и close_data.

ehlo(c connection, domain text) returns reply #

Выполняет начальное согласование с SMTP-сервером с помощью команды EHLO. Сервер возвращает часть своей конфигурации.

helo(c connection, domain text) returns reply #

Выполняет начальное согласование с SMTP-сервером с помощью команды HELO.

help(c connection, command text default null) returns reply #

Отправляет команду HELP. Эта команда может быть реализована не на всех SMTP-серверах.

last_reply(c connection) returns reply #

Возвращает последний ответ SMTP-сервера.

mail(c connection, sender text, parameters text default null) returns reply #

Инициирует транзакцию отправки электронного письма с сервером, отправляя команду MAIL с адресом отправителя.

noop(c connection) returns reply #

Выдаёт команду NOOP. Эта функция в основном используется для проверки соединения.

open_connection(host text, port int default 25, tx_timeout int default null, secure_connection_before_smtp bool default false, verify_peer bool default true) returns connection #

Открывает соединение с SMTP-сервером. Параметр secure_connection_before_smtp указывает, устанавливается ли подключение TLS до соединения SMTP (по сути, если этот параметр имеет значение true, соединение будет использовать SMTPS вместо SMTP). Параметр verify_peer указывает, проверяются ли сертификаты при установке подключения TLS.

open_data(c connection) returns reply #

Отправляет команду DATA, после которой можно использовать функции write_data и write_raw_data, чтобы написать часть электронного письма.

quit(c connection) returns reply #

Завершает сеанс SMTP и отключается от сервера.

rcpt(c connection, recipient text, parameters text default null) returns reply #

Указывает получателя электронного письма. Транзакция отправки сообщения должна быть запущена предыдущим вызовом MAIL, а соединение с почтовым сервером должно быть открыто и инициализировано предыдущими вызовами open_connection и helo или ehlo соответственно.

rset(c connection) returns reply #

Завершает текущую транзакцию отправки письма. Клиент может вызвать rset в любое время после открытия соединения с SMTP-сервером с помощью open_connection до вызова data или open_data.

set_reply_error_check(c connection, enable bool) returns void #

Определяет поведение функции. Если для параметра enable установлено значение true (по умолчанию), любая ошибка на SMTP-сервере выдаёт исключение. Если установлено значение false, для определения ошибки пользователю следует самостоятельно анализировать результаты, возвращаемые функциями.

starttls(c connection, verify_peer bool default true) returns reply #

Отправляет команду STARTTLS для защиты SMTP-соединения с использованием TLS.

vrfy(c connection, recipient text) returns reply #

Отправляет команду VRFY для проверки корректности адреса получателя электронного письма. Эта команда может быть реализована не на всех SMTP-серверах и может возвращать некорректную информацию, поэтому не рекомендуется её использовать.

write_data(c connection, data text) returns void #

Отправляет часть текста сообщения, включая заголовки, SMTP-серверу. При повторном вызове write_data добавляет данные к сообщению.

write_raw_data(c connection, data text) returns void #

Отправляет часть текста сообщения, включая заголовки, 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_connection function.

  • Then send HELO/EHLO command to the SMTP server using helo/ ehlo respectively.

  • Send sender and recipient addresses using mail and rcpt functions.

  • Call the open_data function to start data sending process by sending the DATA command to the SMTP server.

  • After that, write_data and write_raw_data can be called repeatedly to send the actual data.

  • The data sending process is terminated by calling close_data.

  • Once open_data is called, the only functions that can be called are write_data, write_raw_data, or close_data. Other calls result in an error being raised.

  • Alternatively, data sending process can be streamlined with one call of data.

  • After calling close_data or data, the email is sent — call quit to end the connection.

G.12.3. Data Types #

The utl_smtp extension provides the following data types:

  • The reply type 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. reply Parameters

    ParameterDescription
    code 3-digit reply code
    text Text message of the reply

  • The connection type represents an SMTP connection.

    Table G.102. connection Parameters

    ParameterDescription
    host Name or IP address of the remote host when connection is established.
    port Port number of the remote SMTP server connected.
    tx_timeout Time 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_socket This 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(c connection, username text, password text, schemes text default 'PLAIN') returns reply #

Sends the AUTH command to authenticate to the SMTP server. Currently only the PLAIN authentication scheme is supported.

close_all_connections() returns void #

Closes all SMTP connections and releases all associated resources.

close_connection(c connection) returns void #

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(c connection) returns reply #

Ends the e-mail message by sending the sequence <CR><LF>.<CR><LF> (a single period at the beginning of the line).

command(c connection, cmd text, arg text default null) returns reply #

Sends an arbitrary SMTP command and can return a single reply line.

command_replies(c connection, cmd text, arg text default null) returns reply[] #

Sends an arbitrary SMTP command and can return multiple reply lines.

data(c connection, body text) returns reply #

Specifies the body of an email. It is essentially a sequence of calls: open_data, write_data, and close_data.

ehlo(c connection, domain text) returns reply #

Performs the initial handshake with SMTP server using the EHLO command. The server returns a part of its configuration.

helo(c connection, domain text) returns reply #

Performs the initial handshake with SMTP server using the HELO command.

help(c connection, command text default null) returns reply #

Sends the HELP command. This command might not be implemented on all SMTP servers.

last_reply(c connection) returns reply #

Returns the last reply of the SMTP server.

mail(c connection, sender text, parameters text default null) returns reply #

Initiates an email transaction with the server by sending the MAIL command with the sender address.

noop(c connection) returns reply #

Issues the NOOP command. This function is mainly used to check the connection.

open_connection(host text, port int default 25, tx_timeout int default null, secure_connection_before_smtp bool default false, verify_peer bool default true) returns connection #

Opens a connection to an SMTP server. The secure_connection_before_smtp parameter 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). The verify_peer parameter specifies if the certificates are validated when establishing the TLS connection.

open_data(c connection) returns reply #

Sends the DATA command after which you can use write_data and write_raw_data to write a portion of the email.

quit(c connection) returns reply #

Terminates an SMTP session and disconnects from the server.

rcpt(c connection, recipient text, parameters text default null) returns reply #

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 to open_connection and helo or ehlo respectively.

rset(c connection) returns reply #

Terminates the current mail transaction. The client can call rset at any time after the connection to the SMTP server has been opened by means of open_connection until data or open_data is called.

set_reply_error_check(c connection, enable bool) returns void #

Determines function behavior. If the enable parameter 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(c connection, verify_peer bool default true) returns reply #

Sends the STARTTLS command to secure the SMTP connection using TLS.

vrfy(c connection, recipient text) returns reply #

Sends the VRFY command 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(c connection, data text) returns void #

Sends a portion of the text of the message, including headers, to the SMTP server. A repeated call to write_data appends data to the message.

write_raw_data(c connection, data text) returns void #

Sends a portion of the text of the message, including headers, to the SMTP server. A repeated call to write_data appends data to the message. The same as write_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$$;
FAQ