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: listmaster@example.com
test-owner: listmaster@example.com
test-approval: listmaster@example.com
test: "|/home/majordomo/lib/wrapper resend -C /home/majordomo/example.com/etc/majordomo.cf -l test -h example.com -f owner-test test-outgoing@example.com"
test-request: "|/home/majordomo/lib/wrapper majordomo -C /home/majordomo/example.com/etc/majordomo.cf -l test@example.com"
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, test-archive@example.com

(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 Test@example.com 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: <mailto:majordomo@example.com?body=unsubscribe%20$list>
List-Post: <mailto:$list@example.com>
List-Owner: <mailto:owner-$list@example.com>
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</mailto:owner-$list@example.com></mailto:$list@example.com></mailto:majordomo@example.com?body=unsubscribe%20$list>

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 Test@example.com 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: <mailto:majordomo@example.com?body=unsubscribe%20$list>
List-Post: <mailto:$list@example.com>
List-Owner: <mailto:owner-$list@example.com>
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
</mailto:owner-$list@example.com></mailto:$list@example.com></mailto:majordomo@example.com?body=unsubscribe%20$list>

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 test@example.com 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

Comments