Installing Majordomo on a cPanel box with Exim

For the purpose of this tutorial, we'll be installing Majordomo in /home/majordomo/lib and putting our lists in /home/majordomo/{DOMAINNAME}/lists and the {DOMAINNAME} configuration files in /home/majordomo/{DOMAINNAME}/etc. This is my choice and you can choose to install things elsewhere. Note: If you intend on having large lists with attachments, I would recommend NOT installing in /usr/local anywhere, as that is usually smallish. cd /usr/local/src wget http://www.greatcircle.com/majordomo/1.94.5/majordomo-1.94.5.tar.gz tar -zxvf majordomo-1.94.5.tar.gz cd majordomo-1.94.5 Follow the instructions in INSTALL:
Edit Makefile and change settings to point to your compiler, perl and where you will be installing majordomo.
Run 'make wrapper'. You will most likely get a few errors that look like this, and you can safely ignore them. /usr/bin/gcc -DBIN=\"/home/majordomo/lib\" -DPATH=\"PATH=/bin:/usr/bin:/usr/ucb\" -DHOME=\"HOME=/home/majordomo/lib\" -DSHELL=\"SHELL=/bin/sh\" -DMAJORDOMO_CF=\"MAJORDOMO_CF=/home/majordomo/lib/majordomo.cf\" -DPOSIX_UID=91 -DPOSIX_GID=91 -o wrapper wrapper.c wrapper.c: In function ‘main’: wrapper.c:71: warning: incompatible implicit declaration of built-in function ‘exit’ wrapper.c:78: warning: incompatible implicit declaration of built-in function ‘exit’ wrapper.c:81: warning: incompatible implicit declaration of built-in function ‘malloc’ wrapper.c:83: warning: incompatible implicit declaration of built-in function ‘exit’ wrapper.c:143: warning: incompatible implicit declaration of built-in function ‘exit’ wrapper.c:156: warning: incompatible implicit declaration of built-in function ‘exit’ Next run 'make install' and then as root, run 'make install-wrapper'. Following the instructions shown to test the wrapper. You should not see any errors!

Next, lets install the routers in cPanel under Exim Configuration -> Advanced Configuration Editor:

Scroll down until you find the section named Section: ROUTERSTART and enter the following: # This router routes to majordomo majordomo_aliases: driver = redirect allow_defer allow_fail require_files = "+/home/majordomo/${domain}/etc/aliases" data = ${lookup{$local_part}lsearch{/home/majordomo/$domain/etc/aliases}} domains = +local_domains file_transport = address_file pipe_transport = majordomo_pipe retry_use_local_part no_rewrite user = majordomo # This router routes to private majordomo parts. shhh majordomo_private: driver = redirect allow_defer allow_fail require_files = "+/home/majordomo/${domain}/etc/aliases_private" condition = "${if eq {$received_protocol} {local} \ {true} {false} }" data = ${lookup{$local_part}lsearch{/home/majordomo/$domain/etc/aliases_private}} domains = +local_domains file_transport = address_file pipe_transport = majordomo_pipe retry_use_local_part user = majordomo # This router routes unwanted blocked domains from /etc/reject_domains reject_domains: driver = redirect domains = +reject_domains allow_fail data = :fail: The domain $domain is no longer supported (Be sure to change the path to Majordomo if you are installing in a different place from me).

You will also need to add majordomo to the list of trusted users for Exim under Section: CONFIG. You will want to scroll down until you find trusted_users with the Exim Default: unset and the following text underneath: This option is expanded just once, at the start of Exim’s processing. If this option is set, any process that is running as one of the listed users is trusted. The users can be specified numerically or by name. See section 5.2 for details of what trusted callers are permitted to do. If neither trusted_groups nor trusted_users is set, only root and the Exim user are trusted. Next, you need to add the following under Section: TRANSPORTMIDDLE majordomo_pipe: driver = pipe group = daemon return_fail_output user = majordomo Once you have made these changes, click on SAVE at the bottom of the page. cPanel should rebuild the exim configuration file and restart Exim without errors. If you have errors, then you have made a typo in the added settings.

Let's setup our first mailing list 'test@example.com' with user 'example'. First thing is to create the directory structure we will need: cd /home/majordomo mkdir -p example.com/lists mkdir example.com/etc Inside /home/majordomo/example.com/etc is where all the routing and exim email configuring take place. Create the following files :
/home/majordomo/example.com/etc/aliases majordomo: "|/home/majordomo/lib/wrapper majordomo -C /home/majordomo/example.com/etc/majordomo.cf" majordomo-owner: example owner-test: .(JavaScript must be enabled to view this email address) test-owner: .(JavaScript must be enabled to view this email address) test-approval: .(JavaScript must be enabled to view this email address) test: "|/home/majordomo/lib/wrapper resend -C /home/majordomo/example.com/etc/majordomo.cf -l test -h example.com -f owner-test .(JavaScript must be enabled to view this email address)" test-request: "|/home/majordomo/lib/wrapper majordomo -C /home/majordomo/example.com/etc/majordomo.cf -l .(JavaScript must be enabled to view this email address)" test-archive: "|/home/majordomo/lib/wrapper archive2.pl -C /home/majordomo/example.com/etc/majordomo.cf -f /home/majordomo/example.com/lists/test.archive/test.archive -m -a" /home/majordomo/example.com/etc/aliases_private test-outgoing: :include:/home/majordomo/example.com/lists/test, .(JavaScript must be enabled to view this email address) (Credit goes to this site for much of this information).

Next we need to create the mailing list configuration area: cd /home/majordomo/example.com/lists touch test.config test.intro test.info mkdir test.archive test.config needs to include the majordomo configuration file for your list. The following configuration file is something similar to what I use. You really need to familiarize yourself with the various settings and adjust them to suit your own needs: admin_passwd = secretpasswordhere administrivia = no advertise << END END announcements = yes approve_passwd = anothersecretpasswordhere archive_dir = comments << END END date_info = yes date_intro = yes debug = no description = This is a short description of what the .(JavaScript must be enabled to view this email address) mailing list is all about digest_archive = digest_issue = 1 digest_maxdays = digest_maxlines = digest_name = test digest_rm_footer = digest_rm_fronter = digest_volume = 1 digest_work_dir = get_access = list index_access = list info_access = list intro_access = list maxlength = 400000 message_footer << END END message_fronter << END END message_headers << END List-ID: Test Mailing List <$LIST.example.com> List-Unsubscribe: List-Post: List-Owner: END moderate = no moderator = mungedomain = yes noadvertise << END /.*/ END precedence = bulk purge_received = yes reply_to = resend_host = restrict_post = whitelist_in test sender = owner-test strip = yes subject_prefix = [Test] subscribe_policy = open+confirm taboo_body << END END taboo_headers << END END unsubscribe_policy = open+confirm welcome = yes which_access = list who_access = closed In particular you need to change the following: # admin_passwd: Change this to a secret password you will use for admin functions. admin_passwd = secretpasswordhere #approve_passwd: Change this to a secret password you and other list maintainers can use to approve messages, if you use moderation. approve_passwd = anothersecretpasswordhere #description: Set a short description for your list. description = This is a short description of what the .(JavaScript must be enabled to view this email address) mailing list is all about #maxlength: Set a maximum length for your list attachments, if you allow attachments. This is set to 400K maxlength = 400000 #message_headers: You will need at a minimum List-ID to avoid your mailing lists getting trapped by Googles Gmail services. message_headers << END List-ID: Test Mailing List <$LIST.example.com> List-Unsubscribe: List-Post: List-Owner: END #restrict_post: Set this to the name of your list. This will restrict your mailing list to accept only emails from those on your list. # You can enter additional lists. I'll often have a whitelist, which is simply a text file that contains a few privileged users that can post to any list. restrict_post = test #sender: Set this to the email address of account that will be sending the email. sender = owner-test #subject_prefix: Most of my clients like to have a prefix on the subject line so they can easily spot and sort the emails when they come in. subject_prefix = [Test] #subscribe_policy: open+confirm will let any one subscribe once they have confirmed their email address. Setting this to just 'open' is a REALLY bad idea. subscribe_policy = open+confirm #unsubscribe_policy: Pretty self explanatory. unsubscribe_policy = open+confirm #who_access: We set this to closed for all our lists, to avoid people from scraping the email address for spam lists. I'd recommend closed unless you know everyone on the list. who_access = closed test.intro and test.info should contain a short description of what your list is all about.

Finally, add your own email address to lists/test. The format is one email per line.

Be sure to set the file ownership to everything in /home/majordomo/example.com to majordomo: chown -R majordomo: /home/majordomo/example.com Now you just need to test the mailing list out, by sending an email to .(JavaScript must be enabled to view this email address) and see what happens. If everything works as expected, you should get an email back with [Test] prefixed to your subject line. Very the email was archived by looking in /home/majordomo/example.com/lists/test.archive.

Hope this how-to helps out anyone that might be crazy enough to still want to use Majordomo.

Problems: If you get "Trying to exec /home/majordomo/lib/majordomo failed" be sure you have the shebang set properly for Perl. If you installed Majordomo pointing to /usr/local/bin/perl and your perl is at /usr/bin/perl, you can simply create a symlink: cd /usr/local/bin ln -s /usr/bin/perl ./perl