Envio de e-mails demasiadamente lento (Mautic)

Olá, @Gabriel!

Realizei recentemente a migração de um Mautic para Cloud da Oracle, com sua ajuda.

A ideia original dessa migração seria otimizar o envio dos e-mails, que na hospedagem compartilhada antiga estava lentíssimo.

Fiz todas as configurações da máquina seguindo seu curso de Oracle Cloud (com uma máquina de 5 núcleos +24GB e 120GB SSD), setando, inclusive, 4GB de memória para o Mautic, pelas configurações do php. Para minha grande surpresa, ao disparar hoje uma campanha de segmentos (tanto em fila quanto ‘imediamente’) para aproximadamente 20 mil contatos, tivemos novamente uma demora absurda. Não cheguei a cronometrar o envio sem fila, mas em fila, demorou aproximadamente 8 horas para entregar 19000 e-mails. Você pode conferir o e-mail aqui.

Certo que é um e-mail bem formatado, mas acredito que não deveria demorar tanto.

Nas minhas pesquisas pela internet encontrei um tutorial do joeyk (da comunidade do Mautic), mas me pareceu um pouco complicado implementar.

Você saberia me dizer qual seria a melhor forma de otimizar esses envios?

O encaminhamento dos e-mails para a pasta spool (em lotes de 800) ocorreu muito rápido. A demora mesmo se deu para o envio dos e-mails pelo SMTP (mautic:emails:send).

Informações importantes:
Serviço para envio de email: Amazon SES - SMTP
Amazon SES Region: US East (N. Virginia)
Versão do Mautic: v4.4.10

Log de erros do Mautic:

[2024-05-27 05:02:53] mautic.NOTICE: PHP Notice - SessionHandler::gc(): ps_files_cleanup_dir: opendir(/var/lib/php/sessions) failed: Permission denied (13) - in file /var/www/mail.verboencarnado.com.br/htdocs/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php - at line 106 {"maxlifetime":1440} {"hostname":"cloud.verboencarnado.com.br","pid":86536}
[2024-05-27 11:55:17] mautic.NOTICE: PHP Notice - SessionHandler::gc(): ps_files_cleanup_dir: opendir(/var/lib/php/sessions) failed: Permission denied (13) - in file /var/www/mail.verboencarnado.com.br/htdocs/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php - at line 106 {"maxlifetime":1440} {"hostname":"cloud.verboencarnado.com.br","pid":96235}
[2024-05-27 13:41:26] mautic.NOTICE: PHP Notice - SessionHandler::gc(): ps_files_cleanup_dir: opendir(/var/lib/php/sessions) failed: Permission denied (13) - in file /var/www/mail.verboencarnado.com.br/htdocs/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php - at line 106 {"maxlifetime":1440} {"hostname":"cloud.verboencarnado.com.br","pid":98671}
[2024-05-27 11:00:55] mautic.CRITICAL: Uncaught PHP Exception Doctrine\DBAL\Exception\ConnectionLost: "An exception occurred while executing 'SELECT u0_.is_published AS is_published_0, u0_.date_added AS date_added_1, u0_.created_by AS created_by_2, u0_.created_by_user AS created_by_user_3, u0_.date_modified AS date_modified_4, u0_.modified_by AS modified_by_5, u0_.modified_by_user AS modified_by_user_6, u0_.checked_out AS checked_out_7, u0_.checked_out_by AS checked_out_by_8, u0_.checked_out_by_user AS checked_out_by_user_9, u0_.id AS id_10, u0_.username AS username_11, u0_.password AS password_12, u0_.first_name AS first_name_13, u0_.last_name AS last_name_14, u0_.email AS email_15, u0_.position AS position_16, u0_.timezone AS timezone_17, u0_.locale AS locale_18, u0_.last_login AS last_login_19, u0_.last_active AS last_active_20, u0_.preferences AS preferences_21, u0_.signature AS signature_22, r1_.is_published AS is_published_23, r1_.date_added AS date_added_24, r1_.created_by AS created_by_25, r1_.created_by_user AS created_by_user_26, r1_.date_modified AS date_modified_27, r1_.modified_by AS modified_by_28, r1_.modified_by_user AS modified_by_user_29, r1_.checked_out AS checked_out_30, r1_.checked_out_by AS checked_out_by_31, r1_.checked_out_by_user AS checked_out_by_user_32, r1_.id AS id_33, r1_.name AS name_34, r1_.description AS description_35, r1_.is_admin AS is_admin_36, r1_.readable_permissions AS readable_permissions_37, u0_.role_id AS role_id_38 FROM users u0_ LEFT JOIN roles r1_ ON u0_.role_id = r1_.id WHERE (u0_.username = ? OR u0_.email = ?) AND u0_.is_published = ?' with params ["EdV-MaUtIC", "EdV-MaUtIC", 1]:  SQLSTATE[HY000]: General error: 2006 MySQL server has gone away" at /var/www/mail.verboencarnado.com.br/htdocs/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php line 115 {"exception":"[object] (Doctrine\\DBAL\\Exception\\ConnectionLost(code: 0): An exception occurred while executing 'SELECT u0_.is_published AS is_published_0, u0_.date_added AS date_added_1, u0_.created_by AS created_by_2, u0_.created_by_user AS created_by_user_3, u0_.date_modified AS date_modified_4, u0_.modified_by AS modified_by_5, u0_.modified_by_user AS modified_by_user_6, u0_.checked_out AS checked_out_7, u0_.checked_out_by AS checked_out_by_8, u0_.checked_out_by_user AS checked_out_by_user_9, u0_.id AS id_10, u0_.username AS username_11, u0_.password AS password_12, u0_.first_name AS first_name_13, u0_.last_name AS last_name_14, u0_.email AS email_15, u0_.position AS position_16, u0_.timezone AS timezone_17, u0_.locale AS locale_18, u0_.last_login AS last_login_19, u0_.last_active AS last_active_20, u0_.preferences AS preferences_21, u0_.signature AS signature_22, r1_.is_published AS is_published_23, r1_.date_added AS date_added_24, r1_.created_by AS created_by_25, r1_.created_by_user AS created_by_user_26, r1_.date_modified AS date_modified_27, r1_.modified_by AS modified_by_28, r1_.modified_by_user AS modified_by_user_29, r1_.checked_out AS checked_out_30, r1_.checked_out_by AS checked_out_by_31, r1_.checked_out_by_user AS checked_out_by_user_32, r1_.id AS id_33, r1_.name AS name_34, r1_.description AS description_35, r1_.is_admin AS is_admin_36, r1_.readable_permissions AS readable_permissions_37, u0_.role_id AS role_id_38 FROM users u0_ LEFT JOIN roles r1_ ON u0_.role_id = r1_.id WHERE (u0_.username = ? OR u0_.email = ?) AND u0_.is_published = ?' with params [\"EdV-MaUtIC\", \"EdV-MaUtIC\", 1]:\n\nSQLSTATE[HY000]: General error: 2006 MySQL server has gone away at /var/www/mail.verboencarnado.com.br/htdocs/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php:115, Doctrine\\DBAL\\Driver\\PDO\\Exception(code: HY000): SQLSTATE[HY000]: General error: 2006 MySQL server has gone away at /var/www/mail.verboencarnado.com.br/htdocs/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDO/Exception.php:18, PDOException(code: HY000): SQLSTATE[HY000]: General error: 2006 MySQL server has gone away at /var/www/mail.verboencarnado.com.br/htdocs/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:117)"} {"hostname":"cloud.verboencarnado.com.br","pid":99225}
[2024-05-27 14:18:18] mautic.NOTICE: PHP Notice - SessionHandler::gc(): ps_files_cleanup_dir: opendir(/var/lib/php/sessions) failed: Permission denied (13) - in file /var/www/mail.verboencarnado.com.br/htdocs/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php - at line 106 {"maxlifetime":1440} {"hostname":"cloud.verboencarnado.com.br","pid":100358}
[2024-05-27 15:17:31] mautic.NOTICE: PHP Notice - SessionHandler::gc(): ps_files_cleanup_dir: opendir(/var/lib/php/sessions) failed: Permission denied (13) - in file /var/www/mail.verboencarnado.com.br/htdocs/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php - at line 106 {"maxlifetime":1440} {"hostname":"cloud.verboencarnado.com.br","pid":102015}
[2024-05-27 19:02:13] mautic.NOTICE: PHP Notice - SessionHandler::gc(): ps_files_cleanup_dir: opendir(/var/lib/php/sessions) failed: Permission denied (13) - in file /var/www/mail.verboencarnado.com.br/htdocs/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php - at line 106 {"maxlifetime":1440} {"hostname":"cloud.verboencarnado.com.br","pid":107064}
[2024-05-27 19:33:14] mautic.NOTICE: PHP Notice - SessionHandler::gc(): ps_files_cleanup_dir: opendir(/var/lib/php/sessions) failed: Permission denied (13) - in file /var/www/mail.verboencarnado.com.br/htdocs/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php - at line 106 {"maxlifetime":1440} {"hostname":"cloud.verboencarnado.com.br","pid":107750}

Se puder me ajudar ficarei novamente imensamente grato.

Qual limite de envio por segundo da sua conta SES?
O Mautic basicamente coloca os envios em uma fila e o SES envia essa fila.

É possível que o tempo de envio esteja relacionado ao processamento do SES.
Se for este o caso você precisa solicitar um aumento no limite de envio no SES.

Geralmente contas do SES começam com 50.000/dia e 14/segundo.
Mesmo com essa informação no painel o SES dificilmente envia esse volume por segundo.

Você também deve confirmar que fez conexão com o SES por API e não por SMTP.

Algo importante.
Email contendo imagens demora mais.

Também preciso fazer um alerta.
Colocar valores R$ dentro do email aumenta muito a probabilidade de cair no Spam.
Minha recomendação é para colocar os valores apenas na pagina de destino.

Conseguiu otimizar o envio dos emails?

@Gabriel, acabei de fazer a conexão via API. Estou utilizando atualmente o SES de um amigo parceiro da Editora, pois a Amazon insiste em recusar meu pedido para São Paulo. O SES dele está configurado na Virgínia. Será que o fato do nosso server tá aqui no Brasil (pela Oracle) aumente esse tempo de envio?

Ainda não fiz o teste dos envios com a configuração via API.

Ainda tenho dúvidas sobre o envio em fila. Você recomenda que os envios sejam feitos em lotes de 100, mesmo o server tendo uma capacidade maior?

No último envio que fiz (para aproximadamente 20000 leads), recebi no e-mail um número muito grande de reclamações da Amazon (mais de 1000) sobre a entrega para alguns destinatários. O erro estava relacionado à caixa de e-mail de alguns desses leads. Como o número é grande, você acha que pode ter sido por conta de algum problema de configuração do Mautic?

Delivery has failed to these recipients or groups:
The recipient's mailbox is full and can't accept messages now. Please try resending your message later, or contact the recipient directly.
Action: failed
Status: 5.2.2
Diagnostic-Code: smtp;554 5.2.2 mailbox full; STOREDRV.Deliver.Exception:QuotaExceededException; Failed to process message due to a permanent exception with message [BeginDiagnosticData]Microsoft Unified Storage is full. QuotaExceededException: Microsoft Unified Storage is full.[EndDiagnosticData] [Stage: DeliverMessage]
X-Display-Name: =?iso-8859-1?Q?Fl=E1via_Azevedo?=

Você saberia me dizer se esses logs também apontam algum problema em nosso Mautic?

Vamos por partes.

API Amazon SES.
No SES se conectar por SMTP a taxa de envio é limitada, não sei exatamente os limites mas é muito mais lento em comparação com API.
Se agora conectou por API acredito que vai melhorar significativamente.

Sobre o fato de estar utilizando servidor em Virgínia não vai interferir significativamente na velocidade de envio.

Sobre fila, quanto maior o lote mais rápido será o envio.
Neste servidor que está utilizando acredito que lotes em torno de 500 será muito tranquilo.

Sobre o numero de bounces.
Acredito que é por aí mesmo. Um volume como o mencionou de bounces é esperado ao fazer o primeiro envio com SES.
Infelizmente o SES não separa o tipo de bounce. Depois que Google incluiu o Google Fotos no armazenamento muita gente tem esgotado esse armazenamento e isso gera bounce no SES. Esse é justamente o retorno do seu log. Armazenamento do destinatário está esgotado.

Sobre os logs,
Não nenhum registro no seu log está relacionado ao envio dos emails.

Maravilha, @Gabriel. Mais uma vez, muito obrigado pelo suporte e presteza!

Acabei de realizar um novo envio para 20000 contatos (o e-mail tem apenas uma imagem em .jpg, de 13kb - vide link). Fazendo algumas análises da pasta spool com o comando ls | wc, consegui identificar o tempo exato de envios. Uma média de 3,75 e-mails/seg. - 225/min. (utilizando a integração via API).

Agora também consegui compreender a forma como os envios ocorrem. Como selecionei em lotes de 500, ele faz o envio dos 500 e-mails toda vez que a cron mautic:broadcasts:send é ativada, que no nosso caso é de 5/5min. Na análise que fiz, o envio desses 500 e-mails demorou apenas 2 minutos. Fazendo um ajuste do cálculo, para não deixar 3 minutos sem enviar, verifiquei que poderia ter selecionado lotes de 1000.

Estou correto?


Pra tentar evitar o problema com as reclamações dos e-mails, coloquei o Mautic para monitorar uma pasta específica que chamei de Erros filtrando todos os assuntos Delivery Status, Undeliverable e Complaint. Você saberia me dizer se dessa forma ele passará a marcar os contatos com caixa com “Do Not Contact” automaticamente?

Sobre o tamanho do lote, acredito que será bem tranquilo o lote de 1000 neste server, mas ao fazer o envio é bom monitorar o uso de recursos do server com htop.

O tempo de ativação do Cron relacionado a campanhas e listas é bom ter um espaçamento para ter tempo de executar as em sincronia.

O cron de broadcasts pode definir sim um tempo menor, mas é interessante que seja um tempo grande suficiente para que a tarefa seja finalizada antes de executar novamente.

Sobre os bounces, eu faço pelo SNS como mostro no curso.
Já tem muito tempo que não uso caixa monitorada e não me lembro bem como isso funciona.