Maneira segura de enviar mensagens via PHP para muitos usuários

Deixe-me explicar o que quero dizer no meu título. Digamos, por exemplo, que estou criando um pequeno sistema de comércio eletrônico para uma loja / catálogo na web. Existe a possibilidade de os clientes escolherem, desejam receber boletins informativos ou não. Se o fizerem, então, logicamente, os boletins devem ser enviados imediatamente à medida que o boletim é formado e pronto.

Claro que isso pode ser feito de maneira simples, obtendo todos os e-mails de usuários especificados do database e usando for ciclo para enviar mensagens via mail no loop, mas o problema é que me disseram que isso é uma prática ruim. A maneira simples e não barata seria comprar serviço de internet para enviar boletins informativos, mas o que para o programador php é necessário, então?

Então, pergunto-lhe camaradas humildes, o que, do seu ponto de vista, pode ser uma solução?

NB! Você provavelmente não vai acreditar em mim, mas não é para spam.

UPD: talvez eu tenha me explicado errado, mas eu gostaria de ouvir uma solução não só sobre a maneira correta de enviar o correio, mas também sobre a entrega correta. Uma vez que nem todas as mensagens enviadas são sempre entregues.
Claro que existem alguns motivos, que são imprevisíveis. Por exemplo, em algum lugar ao longo do caminho, algo quebrou e o correio foi perdido (se tal é possível), mas também há outras razões que são influenciadas talvez pelo servidor ou em outro lugar. Talvez haja necessidade de conversar com o hoster sobre isso?

Não há razão para que você não pudesse gravá-lo em PHP, embora eu não fizesse parte de um processo webrequest / HTTP. Eu implementei com sucesso para dar ou receber 500.000 assinantes por correspondência (dependendo dos dados locais disponíveis, pois este era um projeto específico da localização). Era um projeto interno, então, infelizmente, nenhum código / pacote para você, mas algumas dicas que eu encontrei:

Configurando a entrega

  • Começou com o phpmailer em si, para cuidar da formatação, codificação de conteúdos e headers, adição de anexos etc. Essa parte dele funciona bem e eu não gostaria de escrever isso do zero.
  • O “envio” de um e-mail em si é apenas a configuração de um sinalizador em um database se / como / o que deve ser enviado para (uma parte) dos assinantes.
  • Depois que esta bandeira é definida, ela será automaticamente apanhada por um cronjob, nenhum servidor web envolvido.
  • Eu comecei com um database altamente poluído com milhões de endereços de e-mail, dos quais muito óbvio não eram válidos, então a primeira coisa era validar todos os endereços de e-mail para o formato, então para o host:
    • filter_var($email, FILTER_VALIDATE_EMAIL); Sobre os assinantes (e, obviamente, obtendo o resultado) livrou-se dos primeiros cem mil e-mails inválidos.
    • Separando o host (e armazenando o nome do host) dos e-mails e validando isso (ele possui um MX ou pelo menos um registro A no DNS, mas tenha em mente: você pode enviar e-mail para um endereço IP foo@[255.255.255.255] , então mantenha esses válidos)) livrou-se de uma boa porção mais. As endereços de e-mail aqui não estão permanentemente desativados, mas com uma bandeira de status que indica que eles estão desativados por causa do nome de domínio / ip.
    • Os scripts foram alterados para exigir endereços de e-mail válidos na inscrição / antes da inserção, esse absurdo de “você não vai conseguir isso” em qualquer lugar, a poluição na base de dados era simplesmente ridícula.
  • Agora eu terminei com uma lista de endereços de e-mail que tinham o potencial de ser válido. Existem, essencialmente, 3 maneiras de detectar endereços inválidos (tenha em mente, tudo pode ser temporário):
    • Eles são negados imediatamente pelo servidor.
    • O servidor determinado anteriormente não escuta o tráfego.
    • Eles são saltados muito tempo depois que você pensou que você os entregou.
  • Coisa estranha, os saltitões, que cada servidor de emails parece ter outro formato e eram um inferno para analisar no início, acabou realmente muito fácil de capturar usando o VERP . Em vez de analisar e-mails completos, um endereço de e-mail dedicado (vamos chamá-lo mailer@example.com) foi configurado para, em vez disso, entregar na checkbox de correio, para transmiti-lo através de um comando e, se enviássemos um email para user@server.tld, o Return-Path foi configurado para mailer+user=server.tld@example.com . Facilmente analisado no recebimento e depois de quantos saltos (a checkbox de correio não poderia existir, a checkbox postal pode estar cheia (sim, ainda!), Etc.) você declarou que uma endereço de e-mail inutilizável depende de você.
  • Agora, a negação direta pelo servidor. Provavelmente, nós poderíamos ter ido configurando corretamente alguns MTA e / ou plugins de escrita para aqueles, mas como os e-mails eram sensíveis ao tempo e tivemos que ter um controle configurável absoluto por correspondência durante o último período de entrega utilizável (após o qual o email não era mais longo de interesse para o usuário), aceleração por servidor de recebimento e, em geral, tudo, levaria ao mesmo tempo a escrever um remetente em PHP, que conhecimos melhor, que usava o protocolo SMTP diretamente para o soquete 25 nos servidores receptores. Com um mínimo de esforço a possibilidade de outro transporte, as opções padrão no PHPMailer foram incorporadas. O protocolo SMTP é realmente bastante simples, mas existem algumas advertências:
    • Um monte de servidor de recebimento aplica Gray Listing: a maioria dos spambots realmente não se importará se um email específico chegar, eles acabam de expulsá-los. Então, se um remetente desconhecido / ainda não confiável enviar email, ele será temporariamente rejeitado. Pegue isso (geralmente código 451) e coloque o e-mail na fila para tentar novamente.
    • Um servidor de mensagens, especialmente dos maiores ISPs e serviços gratuitos (gmail, hotmail / msn / live, etc.) não representará uma torrente de correio sem lutar: depois do primeiro par de cem / mil, eles começam a rejeitar você. Mais sobre isso mais tarde.

Acelerando velocidade

  • Agora, nós possuímos um sistema de entrega que funcionava, mas precisava ser rápido . Enviar 10.000 emails em uma hora está tudo bem se você tiver apenas 10.000 endereços para enviar, mas o mínimo que precisamos era de cerca de 200.000 por hora. O início de um servidor dedicado (que pode realmente ser bastante baixo, sem o que você faz, a maior parte do tempo de envio de e-mail está na rede e não no servidor).
  • Armazenamento em cache de IP: lembre-se de todos os IPs que solicitamos aos nomes de host nos endereços de e-mail? Nós armazenamos esses, obviamente, e pesquisar seu IP de novo e de novo causa atrasos consideráveis. No entanto, os IPs podem mudar: um registro DNS lá, outro MX em outro local … os dados ficam rapidamente velhos. Na maioria das vezes, o servidor não está realmente enviando nada (os boletins de notícias de assinatura vêm em explosões obviamente), um cronjob de baixa prioridade está executando a verificação de todos os nomes de host com um IP obsoleto (nós escolhemos mais velhos 1 dia como estando obsoletos) para um endereço IP , incluindo aqueles que anteriormente não possuíam nenhum (novos domínios são registrados o tempo todo, então, por que um domínio não deveria estar disponível no dia seguinte a que alguém já se inscreveu com entusiasmo com seu novo endereço de e-mail? Ou problemas de servidor com algum domínio são resolvidos, etc.). Na verdade, enviar os e-mails agora não requer mais pesquisas de domínio.
  • Reutilização da conexão SMTP: configurar uma conexão para um servidor leva relativamente uma grande parte do tempo para entregar um e-mail quando você está falando diretamente na porta 25. Você não precisa configurar uma nova conexão para cada email, você pode enviar o próximo sobre a mesma conexão. Um pouco de rastreamento e erro resultou na configuração do padrão aqui para cerca de 50 e-mails por conexão (assumindo que você tem muitos ou mais para o domínio). No entanto, na falha de um endereço de email fechando e reabrindo a conexão para uma tentativa às vezes ajudou. Em suma, isso realmente ajudou a acelerar as coisas.
  • Alguns óbvios, tão óbvio que quase esqueci de mencionar isso: seria um desperdício ter que criar o corpo do e-mail no local: se é um correio geral, prepare o corpo (alterei o PHPMailer um pouco para poder use um email em cache), possivelmente dias antes (se você sabe que vai enviar um e-mail na sexta-feira e seu servidor está inativo, por que não prepará-los na quarta-feira já? Se ele for personalizado, você ainda pode prepará-lo antes do suficiente hora, se não, pelo menos as porções não personalizadas estão esperando para ir.
  • Múltiplos processos. Eu mencionei que o tempo necessário para enviar e-mails é gasto na rede? Um processo de correspondência não está quase obtendo o máximo do seu servidor de emails, carga apenas notável e os e-mails estão escorrendo. Jogue com uma série de processos enviando diferentes porções da fila para ver o que é certo para o seu servidor / conexão, mas lembre-se de 2 coisas muito importantes:
    • Diferentes processos tornam-se muito vulneráveis ​​às condições da raça: freaking absolutamente certo de que você tenha um sistema completo que nunca enviará o mesmo correio duas vezes (três vezes, de mais). Não só irrita os usuários, mas o seu spam aumenta.
    • Mantenha os domínios juntos sempre que possível: escolhendo aleatoriamente a partir da fila, você perderá a vantagem de manter uma conexão aberta ao servidor que recebe o email para o domínio.

Evitando rejeições

  • Você vai enviar muito correio. Isso é exatamente o que os spammers fazem. No entanto, você não quer ser visto como um spammer (afinal, você não está, você está)? Existem vários mecanismos no local que irão aumentar sua confiabilidade aos servidores receptores:
  • Tem um DNS reverso apropriado: processos que verificam o DNS pertencente ao IP que está enviando o e-mail, como muito, se os domínios de segundo nível correspondem: você está enviando o email em nome do exemplo.com ? Verifique se o DNS inverso do seu servidor é algo como somename.example.com .
  • Publique os registros SPF para o seu domínio: indique explicitamente que a máquina usada para enviar seu e-mail em massa é permitida e espera enviar correio com os headers From / Return-Path.
  • Lembre-se de rejeições : os servidores não gostam de lhe dizer repetidas vezes que diferentes endereços de e-mail não existem. Ou mecanismos automatizados, e até mesmo administradores humanos, bloquearam nosso servidor enquanto trabalhamos em todos os endereços de e-mail não-validados que já não existem. Nós não empregamos um duplo opt-in até mais tarde, então o database foi poluído com erros de digitação, pessoas que alternam IPs e, portanto, endereço de e-mail, e-mail e assim por diante. Certifique-se de capturar esses inválidos, e dado o suficiente ou interromper falhas suficientes, desinscreva-os . Eles não estão fazendo nada de bom, estão ajudando resources, e se eles realmente querem você e a checkbox de correio fica disponível mais tarde, eles só precisarão se reinscrever.
  • O DKIM é outro mecanismo que pode aumentar sua confiabilidade, mas como não o implementamos (ainda assim), não posso te contar muito sobre isso.
  • Registros MX: alguns servidores ainda gostam se o seu servidor de envio também for o servidor receptor do domínio. Como era na época, tivemos apenas 1 MX, e como o servidor de correspondência ainda não era tão ocupado, apelidávamos do servidor MX de retorno para o domínio. O servidor MX normal não era o servidor que enviava as assinaturas, pois é muito irritante ser temporariamente bloqueado por um servidor que você está tentando enviar um e-mail importante para (clientes etc.) porque você já enviou uma carga de correio menos importante. Ele tem a preferência mais alta como o recebimento de MX, mas no caso em que falharia, tivemos o bom bônus de que o nosso servidor de envio de assinaturas ainda seria um retorno para a entrega, então, em crise, ainda podemos conseguir isso, evitando rebotes estranhos aos clientes tentando para nos alcançar.
  • Diga-lhes sobre você. A sério. Muitos jogadores importantes em endereços de e-mail gratuitos, como o live.com, oferecem-lhe a oportunidade de se inscrever de alguma forma, ou ter algum ponto de contato para ir para obter ajuda e suporte se seus e-mails forem rejeitados. Eu tenho uma razão legítima para enviar tantos e-mails, e é credível que você tenha muitos assinantes, é provável que eles sejam sérios no número de e-mails que você pode enviar para o servidor por hora. Um milho magra pode se tornar em algum lugar nos dez mil ou mesmo maior se você for persuasivo e honesto. Pode haver contratos, requisitos que você precisa cumprir e promete que você deve (e manter) ser permitido isso. Os ISPs são marcas distintas e todos os outros jogadores são diferentes. Não se preocupe em chamá-los geralmente, porque 99% do tempo os únicos números que você pode encontrar só terão pessoas dispostas a solucionar sua conexão com a internet, que entende (ou é permitido) pouco mais. Um abuse@ endereço de e-mail é um bom lugar para começar, mas veja se você pode investigar um endereço de e-mail mais direto de algum lugar. Seja preciso, honesto e completo: aproximadamente quantos subscritores você tem uma endereço de e-mail com esse ISP, com que frequência você está tentando enviá-los, quais são os erros ou recusas que você recebe, como é o processo de inscrição e inscrição, e o que é? o serviço que você realmente fornece aos seus clientes. Além disso, seja bom: o quão vital o envio desses mails pode ser para o seu negócio, entrar em pânico sobre isso e reivindicar perdas terríveis não diz respeito a eles. Uma declaração educada de fatos e desejos, e perguntar se eles podem ajudar em vez de exigir uma solução vai muito longo caminho.
  • Throttling: tanto quanto você tentou, algum servidor aceitará apenas uma certa quantidade de correio por hora e / ou dia de você. Aprenda esses números (estamos logando sucessos e falhas de qualquer maneira), configure-os para um padrão razoável para os domínios normais, configure-os para os limites acordados para jogadores maiores.

Evitando ser marcado como spam

  • Primeira regra: não spam!
  • Segunda regra: sempre! Não é “uma vez”, nem “não se inscreveram, mas esse pode ser o negócio da vida para eles”, não com as melhores intenções, as pessoas tiveram que pedir seus e-mails.
  • Obviamente, configure um mecanismo de assinatura opt-in duplo correto.
  • O PHPMailer estabelece headers apropriados por conta própria,
  • Configure um mecanismo fácil de cancelar a inscrição, pela web (inclua um link para ele em cada mail), possivelmente também e-mail e serviço de clientes, se você tiver. Certifique-se de que o serviço de clientes possa cancelar a inscrição das pessoas diretamente.
  • Como disse anteriormente: cancelar (excessivo) falha e salta.
  • Evite as palavras-chave do “spam” de uma vida.
  • Use url’s em seus e-mails com moderação.
  • Evite adicionar links para domínios fora do seu controle, a menos que você esteja absolutamente seguro de que pode confiar neles para não spam, mesmo assim …
  • Fornecer valor para o usuário: ser marcado como spam por interação do usuário em clientes google / yahoo / live webmail prejudica gravemente os sucessos futuros (em uma nota do site: se você se inscrever, live / msn / hotmail encaminhará todo o email para você envie pelo seu domínio que é marcado como spam pelos usuários. Aprenda a adorá-lo e, como sempre: desinscreva-os, eles claramente não querem seu shopping e estão prejudicando sua sorting de spam).
  • Monitorar listas negras para o seu IP. Se você aparecer em um desses, é tchau bye, então a ação imidiate em ambos, limpar seu nome e determinar o caso é necessária.

Medição da taxa de sucesso

  • Com todo o processo sob seu controle, você tem certeza de que o e-mail terminou em algum lugar (embora possa ser o bitbucket do MX ou uma pasta de spam), ou você registrou uma falha e o motivo. Isso cuida dos números “realmente entregues”.
  • Algumas pessoas vão tentar convencê-lo a adicionar links para imagens on-line aos seus e-mails (real ou famoso gif transparente 1×1) para medir quantas pessoas realmente lêem seu e-mail. Como uma porcentagem elevada bloqueia essas imagens, esses números são instáveis ​​no máximo, e acreditamos que não devemos incomodar com eles, seus números são totalmente confiáveis.
  • Sua melhor aposta para medir a taxa de sucesso real é muito mais fácil se você quiser que os usuários façam algo. Adicione parâmetros aos links no correio, para que você possa medir quantos usuários chegam ao site que você ligou, se eles realizaram as ações desejadas (assistiu um vídeo, deixou um comentário, comprou bens).

Em suma, com todo o log, a interface do usuário, configurações configuráveis ​​por domínio / e-mail / usuário, etc. Levamos cerca de 1,5 milhões de homens para construir e corrigir as peculiaridades. Isso pode ser bastante um investimento em comparação com a terceirização dos e-mails, pode não ser, tudo depende do volume e da própria empresa.

Agora, deixe o fogo começar que eu era um idiota para escrever um MTA em PHP, para um que gostou muito dele (o que é uma razão pela qual eu escrevi essa enorme quantidade de texto) e as capacidades de logging e configurações extremamente versáteis, por host alertas baseados na porcentagem de falha, etc, estão tornando a vida tão fácil;)

Usar algo como Swiftmailer , PHPmailer ou Zend_mail são alternativas muito melhores para usar a function mail() simples mail() , pois pode ser facilmente marcado como spam. Há simplesmente demasiados problemas com a correspondência que precisam ser considerados – a maioria deles é resolvida usando bibliotecas pré-existentes.

Apenas alguns problemas que precisam ser abordados ao enviar emails de massa manualmente:

  • Usando headers incorretos.

  • Processando mensagens rejeitadas

  • Tempo de caducidade devido a um astream de e-mails.

Editar:

Provavelmente não é a resposta que você está procurando. Mas, eu sugeriria fortemente que você investir em algo como o Monitor de campanha ou Mail Chimp . Uma vez que este processo não é para fins educacionais, mas comercial, eu sugiro fortemente os serviços acima.

Eu recebi sua pergunta, mas antes de responder, deixe-me ir às considerações usuais. Primeiro, recomendo fortemente o uso de um serviço como Mail Chimp. É um pouco grátis para pequenos empregos e tem muitos resources legais, como rastrear quantos e-mails estavam abertos, quantos foram clicados, quantos falharam em entregar … Pense em fazer um favor para si mesmo e não reinventar a roda.

Agora, para conhecer o propósito, vamos para a resposta à sua pergunta.

A primeira coisa a ter em mente é fazer cumprir sua lista para ser uma boa. Como fazer isso? Bem, para uma boa lista, quero dizer uma lista de endereços de e-mail válida. Simples colocar um formulário de boletim informativo em sua página, com apenas um campo (talvez um captcha, mas eu não acho que seja necessário).

Salve todas as inputs em uma tabela de database, com um campo “isValid” definido como falso por padrão e qualquer tipo de hash exclusivo. Em seguida, você envia um email de confirmação, com um link (com o hash gerado) para confimação que, quando clicado, fará a bandeira “isValid” verdadeira e um link para cancelamento (SEMPRE envie este link de cancelamento em todos os seus e-mails).

Isto é o que as lojas e sites sérios fazem. Qualquer coisa que obriga seus clientes / visitantes a receber é uma prática moral ruim (ou seja, spam).

Segundo, use um bom serviço de hospedagem. Os serviços muito baratos costumam ser usados ​​por spammers, e os principais serviços de e-mail preenchem tudo o que vem desses endereços.

Eu sei, você deve estar se perguntando se eu começo sua pergunta errada. Não, eu não, material técnico vem agora.

Por que uma má prática coloca uma function de correio dentro de um loop for? Simples. Como o correio de function faz várias operações sempre que é chamado. PHP, abrirá uma conexão com o servidor de email, enviará os dados a serem analisados, solicitará o envio, registrar o status do servidor de correio, fechar a conexão, aumentar o estado de explosão para finalizar a function de correio que você chamou e limpar a bagunça da memory.

Esta sobrecarga de conexão é o problema que as pessoas afirmam como má prática do ponto de vista da programação. Usar uma solução SMTP / IMAP é melhor porque otimiza esse processo.

Um pouco sobre as coisas de tecnologia, vejo suas perguntas sobre a entrega. Bem, como eu disse, você tem algumas maneiras de garantir que sua lista de emails seja boa o suficiente. Mas e se ocorrer outra exceção, como ter falhas de apagão + sem interrupção no servidor do cliente?

Bem, o PHP mantém o status de “pedir ao servidor de correio para enviar, enviar servidor de correio”. Se o servidor de correio enviou sua mensagem, o PHP retornará verdadeiro. Período.

Se o cliente não puder receber ou rejeitar, você deve verificar os headers dos e-mails e o status do e-mail. Estes estão no servidor de e-mail. Mais uma vez, essas informações podem ser acessadas com extensões SMTP / POP / IMAP, não com function de correio.

Se você quiser ir mais longe, leia documentos do IMAP, procure por classs de e-mail (phpclasss.org, pear e pecl são os melhores lugares para procurar).

Dica extra: os RFCs podem ser úteis, pois você pode entender melhor o que os servidores de e-mail realmente conversam um com o outro.

Dica extra 2: Acesse você gmail ou ymail e verifique se as suas mensagens enviadas / recebidas são “versão completa” e leia seus headers. Você pode aprender muito com eles.

Basta usar o PHP Mail e estudar o FMI e como criar headers personalizados você pode append o quarto parâmetro, o exmaple segue

  ...  '; // To send HTML mail, the Content-type header must be set $headers = 'MIME-Version: 1.0' . "\r\n"; $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n"; // Additional headers $headers .= 'To: Mary , Kelly ' . "\r\n"; $headers .= 'From: Birthday Reminder ' . "\r\n"; $headers .= 'Cc: birthdayarchive@example.com' . "\r\n"; $headers .= 'Bcc: birthdaycheck@example.com' . "\r\n"; // Mail it mail($to, $subject, $message, $headers); ?> 

Fonte: http://php.net/manual/en/function.mail.php

crie um subsistema de fila de correio que pode include tabelas como mail_queue, mail_status, mail_attachments, mail_recipients e mail_templates etc …

Você pode considerar PHPMailer http://phpmailer.worxware.com/index.php?pg=exampleasendmail

Você pode adicionar vários destinatários e uma function de retorno de chamada especial para lidar com as mensagens que retornam para cada correio enviado. (para um exemplo, visite o link)

Eu não acho que a captura de um “erro de entrega de correio falhou” é possível via FTP, exceto que você está usando o PHPMailer via SMTP e, de vez em quando, assista a qualquer mensagem de retorno de qualquer destinatário da sua coleção de e-mail de saída.