Forwarding email to distribution list - php

I recently had to move servers. On the old server, I had a Mailman listserv distribution list, but since Mailman was not supported on the new server, I wrote up a PHP script to read messages from IMAP and resend via SMTP. The script is brittle (my fault) and complex (not my fault): I'm having to parse each message, find the bits that I can use (if it's multi-part or HTML or it has attachments), and then reconstruct the message for SMTP so that each member except the sender gets a copy and the Reply-To is the distribution list address. The thing is, I know that the raw source of the message is fine as is. I just need to change/add a few headers.
On Windows servers, you can configure an email dropbox folder where you could save outgoing mail messages in their raw form. Is there anything similar on *nix? Is there any other method I should look at?
I know I can set up a forwarder address on the server, but I really like the behavior of listserv systems: senders don't get a copy of their own message, the subject is identified with the list's label and hitting "Reply" sends a message back to the distribution list, not the original sender.

In order to create your own bespoke list server system you'll need to do the following:
Configure your mail server to have an alias such as no-reply#yourdomain.com to redirect messages to black-hole or /dev/null or something like that, basically deleting any messages on arrival without returning NDR (non-delivery report) email messages to senders. This is the address your script will use in the To: header of your email messages when sending to the group.
Write your PHP script section that sends to the group in such a way that: (a) first pulls all your subscribers out of a database (or securely stored data file) into an array, (b) next remove the message author's address from the array, (c) then finally loop through all the remaining subscribers in the array in batches of about 15 recipients and send the message with the mail() function using To: "Your List Name" <no-reply#yourdomain.com and the BCC: (blind carbon copy) field to prevent receipients seeing who else is on the list.
If you're wanting to try out some of the existing solutions for this why not take a look at
Majordomo.

Related

Trace not delivered / bounced email with PHP, phpmailer and Message-ID

I have a PHP web app with a section to send invoice by email to all partners.
Each partner could have more than 1 email.
For example: COMPANY-1 with emails: email_1#company1.com and email_2#company1.com
I send all with phpmailer.
I save into my database the send-response from server mail ( in this case gmail).
If sent, i'll save true, else false - foreach email.
But some emails sometimes are incorrect (due to error typing when insert) or are dismissed by the company (in this case the company do not inform us and we still send to this deleted email) and I like to retrieve these "problems" using web app.
(If I login into google webmail I can see the email returned for each sent to an not existing email, with some advice/error code inside... but i don't know how to retrieve using PHP)
I tried using
$inbox = imap_open($hostname,$username,$password);
$emails = imap_search($inbox,'ALL');
This script works, but using ALL i get timeout.
I don't know the best method to retrieve these email of "NOT DELIVERED EMAILS FOR SOME PROBLEMS".
My first ideas was to set a custom Message-ID in the header when I send:
$messageID = "<" . md5($_SERVER['HTTP_HOST'].(idate("U")-1000000000).uniqid()).'-'.idate("U") . '#' . $_SERVER['HTTP_HOST'] . '>';
$mail->MessageID = $messageID;
and then in my script, using a command like:
$messageID = retrieve_from_database(...);
$emails = imap_search($inbox,'HEADER ' . $messageID);
but it doesn't exist a query HEADER
I'd like in my web app to show, for each email sent, eventually problem of bounced or undelivered but I don't know how and what I need to "ask" to imap_search to retrieve responses associated to the original sent email.
I read criterias list from docs, but I don't find anything usefull I think: https://www.php.net/manual/en/function.imap-search.php
Example of a scenario I need:
I send an email with Message-ID: <test#testXYZ> from my_email#mywebapp.com to email_not_existing#test.com. The server response true cause sent is done.
I insert a new entry on my database table emails_sent with send result true: INSERT INTO emails_sent (ID, email_dest, sent, MessageID, when) VALUES (455, 'email_not_existing#test.com', TRUE, $messageID, '2019-05-30 8:00:00')
The gmail daemon reply to my_email#mywebapp.com with a message of undelivered email
In my web app, when I go into page of sent emails, foreach ID from emails_sent table, i need to search on imap eventually response email with errors. In this example case when I ask for ID 455, I need to search on imap_search messages replyes associated with my email sent with MessageID assigned by me (or other method i don't know....)
I would advise you to get away from shared hosting and get a proper server (try scaleway.com). As you're discovering, it means you don't get sufficient control.
I'd recommend against using IMAP as your database - as you're finding it's not good enough for the kind of searching you want to do. If you import all the bounced messages into your own DB, you're free to parse and search in whatever way you like, and it's also easy to get all messages from IMAP.
The most efficient way to handle bounces is to get your SMTP server to pipe bounce messages directly into a script. This will give you the complete bounced message, along with environment variables that tell you more about the delivery. That of course requires that you have config-level access to your mail server, or a hosting provider with a clue.
Be warned that bounce handling is an exceedingly unpleasant task, and is very difficult to do well. You may want to look at a 3rd-party bounce handler like Boogie Tools bounce studio to save you some sanity! Aside from some very broad top-level standards, there is very little consistency at a lower level, and bounces are often useless. For example, MS Exchange can produce bounces that do not contain the bounced message's original target address at all! The way around this is to use VERP, where every address (or even every message) gets its own unique return path, allowing you to know where a message bounced from even if the message content contains no clues.

php imap: can't see actual recipient if bcc

I'm working with PHP IMAP functions to poll an inbox and process the emails. Sometimes the emails are received via bcc -- this email was bcc'd by the sender. I need to be able to retrieve the actual email bcc'd -- but imap_fetchheader and imap_rfc822_parse_headers don't provide that if the recipient is bcc'd (even though it's in the return spec).
The issue is that I'm using plus addressing (myemail+value#domain.com) as part of my script, so it's not sufficient to know the email landed in my inbox -- I need to know the specific version of the address it was emailed to.
I understand the whole purpose of bcc is to be hidden. But I would think that there should be something in the header of the bcc-recipient to indicate the email was sent to them.
The "bcc address" that message is sent to is not part of the message itself, it is part of the message exchange protocol. It is used on the protocol level of smtp whilst handing over the message to the receiving server. The content that is handed over, so the message payload itself, is something different. There is no way to read that address from a received message by means of a protocol like imap4 or pop3. You'd have to scan and parse the smtp servers log files for that.
You can easily check that yourself: open the source code of a message received. So the original, technical payload including everything. That looks ugly, but it shows all information actually contained in the data. You will not see any mentioning of "bcc" or a "bcc address" in there.

Bounce invalid dynamic email address from PHP through postfix pipe

I have a web application in PHP that allows users to create documents and send them as PDF attached to an email.
Originally, it was sent with a reply-to pointing to the user's email address, but I am implementing an internal email address system. The goal is to keep all the replies to the original email related to a specific document in the application.
All internal addresses start with PREFIX followed by delimiter "-". Postfix processes all email sent to PREFIX#mydomain.com through a pipe to a PHP script that tries to match the address to a specific user and document (eg: PREFIX-U1A-DJX8#mydomain.com refers to document JX8 of user 1A)
Everything works well but I am wondering how to handle invalid emails:
When no document is found related to the address, it is most probably spam.
However it's possible someone manually wrote the address and was mistaken, in that case the sender should be notified.
Should I simply send a generic mail from the PHP script to the sender stating the address is invalid?
Or is there a way to send a bounce either through the script or to tell postfix to handle it?

Bulk Search E-Mail Headers

I would like to find out all e-mails that have been received by our mail server from a particular IP address, contained in the Message Headers.
It is a static IP, and I have found some already by manual means, but I am trying to find a way to either do this programatically, perhaps using a PHP script with full access on my mail server, or perhaps there is a function within cPanel itself which will do this?
How would one go about searching all e-mail headers for this IP?
You may want to have a look at procmail. It's a tool that can be used to process email messages as they arrive to your mailbox. You can specify the processing on the email message based on any field in the message header. In your case, you would be considering the "Received:" field which displays the IP address upstream email server.
Although procmail is generally used for processing email as it arrives, it is also possible to use it to process existing mail stored in mailboxes if you can cat and pipe the messages from the mailbox to procmail.
There is a simple example in the link below that explains the basics of using procmail.
Howto filter and forward e-mail with procmail: example

PHP detect and store returning emails

I'm sending some newletters using PHP mail() with a Sender address.
For some reasons that I will have to check, many of these newlsetters are bounced and return a "failure notice" to my Sender address.
At the moment these emails are simply returned to the email client where we read the emails of the Sender.
I wish I could store and manage all these "failed" email addresses for my marketing staff.
Of course it is very hard to copy/paste each email address from the email client (they are hundreds).
Is there a way to detect and catch via PHP these addresses to be stored in a Mysql table?
Thanks in advance.
You can't get the information about failed messages from the mail() command as this only sands the message to your local mail server for handling.
You will need to implement a cronjob or otherwise regularly called script that will check the mailbox. So you will need to use the IMAP and POP functions in PHP to fetch the messages and process failed messages.
Or you will need to check the manual for your mail-server to check if you can include some code to execute when the server encounters a failure. So the mailserver itself will flag the failed messages inside your database or at least calls a script providing it with the failed message.
The customary solution to this is VERP http://cr.yp.to/proto/verp.txt -- basically, use a unique envelope sender for each message; anything sent back to that particular address is a bounce, from the address you tried to send to.
For example, if your list is called fnord#example.org and you send message 12345 to djb#example.net.invalid then the envelope sender for that message would be something like fnord-12345-djb=example.net.invalid#example.org and your MTA should be configured to route any email to this address to the correct place (a script to remove the failed address from your database, or whatever).
Of course, if you use a proper mailing list manager (and you should!), it will already contain the logic to take care of all of this; it should be a simple matter of configuration.

Categories