[identity profile] codeswitcher.livejournal.com posting in [community profile] cs_hackerary
Enabling plus addressing in Cpanel should be easy, what with all the layers of email filtering it presents the domain owner. The way to enable plus addressing is to filter incoming email on the basis of to whom its addressed. If you're fred@domain.tld, and want plus addressing to work, all forms of fred+arbitrarystring@domain.tld need to get routed to fred@domain.tld. That's a job for email filtering.

Alas, Cpanel presents the user with no way to filter incoming email on the basis of who it's really addressed for, i.e. the recipient specified in the envelope of the message. This is the address you really want for filtering, because without it, BCC and email list messages aren't delivered when you try to filter on the recipient. To add insult to injury, a "Envelope-to" field is added to messages at delivery -- after all filtering is done.

Cpanel is exim under the hood, and, frankly, the best thing about cpanel+exim is that it allows you to call out to some other real filtering program, if available.

And procmail, which is such a real filtering program, is on many linuxes by default. And it, in turn, can call perl so you can really get something accomplished.

So the answer to "How can I filter by the Envelope-To in cpanel+exim?" is "You can't. But you can call something that can."


Before proceeding with the following instructions, please be cognizant that you can deeply bork your email system this way. Actually, you pretty much inevitably will in the course of getting everything right. You may not want to do this for the first time on a system with actual users getting their mail on it. Just saying.

1) IN CPANEL: Create a "catch-all" email account. This is an email account which is where all your mal-addressed email and random dictionary attack spam will wind up. I call mine "lostandfound@mydomain.tld", so that's what I call it below. No, this is not optional.

2) IN CPANEL: Go to "Default Address". Use the pull down to select the (first) domain you want to do this to, e.g. "mydomain.tld". Click "Forward to email address" and specify your catch-all address. You can come back later to do this to any other domains you're rolling this feature out for.

Note to the indignant: yes, you have to have a catch-all. If you don't turn on a catch-all, exim will bounce all email to fred+anything@domain.tld as "user not found" before anything further happens. You are welcome to try to implement bouncing manually in your procmailrc, but these instructions do not cover that.

3) IN CPANEL: Have email accounts set up for each stem (e.g. "fred", "emily", "theboss") you want to have email accounts for.

4) IN THE FILE MANAGER (which you get to via cpanel): create a directory in the root of your account (usually /home/$username) called something like "procmail".

5) IN THE FILE MANAGER: create three directories in your new /home/$user/procmail folder: "bin", "logs", and "rc".

6) IN THE FILE MANAGER: In /home/$user/procmail/bin create a new file called "cleanfrom.pl".
6a) Change its permissions to at least 744 or whatever your mail server will require to be able to execute it.
6b) Using the "Code Editor" (chose "UTF-8" encoding if asked), put the following contents in it:
#!/usr/bin/perl -wT

$_= $ARGV[0];
if ( /\b(\S+\@\S+)\b/i ) { 
    print $1;
}
and save and close it.

7) IN THE FILE MANAGER: In /home/$user/procmail/rc create a new file called "main".
7a) Using the "Code Editor" (chose "UTF-8" encoding if asked), put the following contents in it:
###################################################################
# ~/procmail/rc/main  The Main Procmailrc for YOURDOMAINSHERE
###################################################################
#
# WARNING!!  THIS procmailrc MUST NEVER DELIVER TO A MAILBOX
# (except for diagnostics, use ~/procmail/logs/audit/.)
# cause procmail doesn't apparently write anything this system 
# reads.  So, all recipes must FORWARD to an email address
# using the bang invocation of sendmail, a la:
#    :0 w    # pass along all other mail
#    ! -oi -f "$SENDER" "$@"
#
# THE BASIC IDEA:
# Exim is apparently(?) a miserable excuse for a filter and cpanel
# just makes it even more limited.  The most basic of all
# email filtering functionalities is the ability to discriminate
# on the basis of the "RCPT TO", which is not exposed in 
# cpanel's account level or user level filtering options, and which
# it only writes to the message -- get this -- AT DELIVERY, yes,
# after all filtering is done.  Way to go exim/cpanel.
#
# Fortunately, exim exposes (well, it can, and this host does) 
# the RCPT TO in a pair of environment variables, LOCAL_PART
# and DOMAIN.  Even more fortunately, you can call procmail
# through exim's pipe feature to get at a real filtering system.
#
# This procmailrc does three simple things to all messages:
# 1) Add a header field X-RCPT-TO with the appropriate value in it.
# 2) Add a header field X-RCPT-TO-ADDED with the value
#       "X-RCPT-TO added with procmail because exim cannot"
#    which gives exim something handy to search on in the "Any 
#    header" condition, by which we may prevent loops.
# 3) Send the email on to where it's supposed to go, which in
#    the case of plussed addresses, is to their stems.
#
# All stems must be set up as accounts and may have forwarders.
#
# This procmailrc is called from an ACCT level filter, on the
# criterion that no header fields contain "X-RCPT-TO added with 
# procmail because exim cannot".  The pipe is:
#	/usr/bin/procmail -m -p /home/$user/procmailrc/main
# where "$user" us replaced with your homedir.
###################################################################

MYDIR = /home/YOURUSERNAMEHERE
THISFILE = "${MYDIR}/procmail/rc/main"

LOGFILE= ${MYDIR}/procmail/logs/log.main
LOG="
BEGIN
THISFILE: $THISFILE 
"

# Get ENVFROM
:0 wh
ENVFROM=| formail -x 'From '

LOG="Envelope From: $ENVFROM
"
# Clean up ENVFROM
ENVFROM=`${MYDIR}/procmail/bin/cleanfrom.pl "$ENVFROM"`
LOG="Addressed from: $ENVFROM
"

# Get RCPTTO
RCPTTO="${LOCAL_PART}@${DOMAIN}"
LOG="RCPT TO: $RCPTTO
"

# Write RCPTTO to the msg as X-RCPT-TO
:0 fwh
| formail -i "X-RCPT-TO: $RCPTTO"

# Add X-RCPT-TO-ADDED header for loopstopping
:0 fwh
| formail -i "X-RCPT-TO-ADDED: X-RCPT-TO added with procmail because exim cannot"


#############
# Let's see what the incoming email looks like at this point
# shall we?  Uncomment the next bit to deliver to the audit directory
# for inspection.  ${MYDIR}/procmail/logs/audit/ had better exist
# before you try to use it.
############
#
#:0 c
#${MYDIR}/procmail/logs/audit/.
#

:0
* DOMAIN ?? mydomain\.tld$
{
	:0
	* RCPTTO ?? ^fred(\+|-|_|)
	! -f "$ENVFROM" "fred@mydomain.tld"


	#Must be final line, for mal-addressed and crap email
	:0 
	! -f "$ENVFROM" "lostandfound@mydomain.tld"
}

:0
! -f "$ENVFROM" "mydefaultaccount"
Save it.
7b) Now, go back and edit it to match your domain and users and account:
7bi) Find "YOURDOMAINSHERE" at the top, and replace it with the domain(s) you're running through this thing. NOTE: this single procmailrc file is intended to handle ALL the domains you have on this hosting account. Don't have separate files for separate domains; it won't work. (If you know about the procmail INCLUDERC or SWITCHRC recipes, you can use them to factor your code into subfiles on a by-domain or by-whatever-you-like basis.)
7bii) Find "YOURUSERNAMEHERE" near the top of the code, and change it to the name of your actual account (the resulting string should match what it says in the parent-most folder of the File Manager.)
7biii) Find "mydomain\.tld" and change it to whatever domain you're doing this to. Note that you have to escape the dot with a "\". Note that as per my example, fred@www.mydomain.tld will get forwarded to fred@mydomain.tld, because I think that's a feature. If you don't want that, you can stick a ^ in front, e.g. ^mydomain\.tld$ to turn that off. Also please note that you may have this work on more than one domain. All the accounts for a domain are contained within a chunk of code like so:
:0
* DOMAIN ?? mydomain\.tld$
{
	.
	.
	.
}
You can just follow it with
:0
* DOMAIN ?? mycompletelyotherdomain\.tld$
{
	.
	.
	.
}
and so forth. Within the curly braces are the recipes (that's what we call them in procmail land) for each of the stem addresses/users at that domain. So for each user you've got at that domain, put a chunk of code like so:
	:0
	* RCPTTO ?? ^fred(\+|-|_|)
	! -f "$ENVFROM" "fred@mydomain.tld"
only replace "fred" (both times!) with the stem/username of the account. Be sure that the last recipe within a set of curly braces is the catch-all (you can have different catch-alls for different domains or not, up to you where you want your flood of spam to go). Or, you know, route it to /dev/null -- which you can totally do in procmail if you don't mind maybe accidentally nuking email you cared about. Maybe do that after setting everything up and testing it throughly, nu?

Anyways: save your procmail/rc/mail file. Please note that this is called a "procmailrc" (note the two letters on the end) in procmail land, and is traditionally named .procmailrc, which we aren't doing because of reasons.

8) IN CPANEL: Go to "Account Level Filtering". VERY IMPORTANT: do not confuse this with "User Level Filtering". The latter won't cut it. Hit "Create a New Filter".
8a) Name the filter something suggestive of what it's for, like say "Procmail".
8b) For the Rules, select (first pulldown) "Any header" and (second pulldown) "does not contain", then put in the text box, "X-RCPT-TO added with procmail because exim cannot". Cut and paste with care because you have to get that exactly right, with no additional spaces at the beginning or end.
8c) For the Actions, select (first pulldown) "Pipe to a program" and then fill in the textbox:
/usr/bin/procmail -m -p /home/YOURACCOUNT/procmail/rc/main
(only replace YOURACCOUNT with your account name.)
8d) Hope like crazy that procmail is in the default location, and click "Save."

9) Go test your system vigorously. Email to fred@mydomain.tld should go to fred@mydomain.tld. Email to fred+whatever@mydomain.tld should go to fred@mydomain.tld. Email to emily@mydomain.tld but BCC'd fred+whatever@mydomain.tld should go to both emily@mydomain.tld (if it exists, or lostandfound@mydomain.tld if it doesn't) and fred@mydomain.tld. Email to fredwhatever@mydomain.tld should go to lostandfound@mydomain.tld.

If you both did all the above right, and everything on the back end is configured compatibly, you'll have a working system.

Things that could go wrong:
procmail isn't where we hoped it would be -- so make a php script which makes a system call to "whereis procmail" and returns the result on the screen or in an email. If it's anywhere, that will report it to you. Also, if necessary, you can use the whereis trick on perl and formail, two other programs this system requires.

exotic technical errors in bounced test messages/permissions may be wrong -- check to make sure everything is as executable as you need it to be.

everything winds up in the catchall/procmail has a blank RCPTTO -- you can find this out, btw, by viewing /home/YOURACCOUNT/procmail/logs/log.main, which is a record of everything your procmailrc delivered and what it thought was going on when it did. If procmail can't see the values in $LOCAL_PART and $DOMAIN, then exim isn't exporting those variables to the environment. You'll have to ask your sysadmin to make it do that.

Finally, note that in your procmailrc, there's a line
| formail -i "X-RCPT-TO-ADDED: X-RCPT-TO added with procmail because exim cannot"
. You may change what's between the quotes to be whatever string you want so long as it starts with "X-" and has a colon hard after the first word with no space. Whatever you change it to, it's what's after the colon and the following space which the Account Level Filter rule needs to match on. This line will be secretly buried in all users' incoming email headers. You are welcome to personalize it. Just make sure it's not something that might coincidentally appear in any other header field (would cause false positives on the filter) -- and nothing that will piss off your users.

Profile

cs_hackerary: (Default)
Codeswitcher's Hackerary

March 2022

S M T W T F S
  12345
6 789101112
13141516171819
20212223242526
2728293031  

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Aug. 12th, 2025 12:48 am
Powered by Dreamwidth Studios