Linux UUCP and sendmail

uucp ("Unix to Unix Copy") is a store-and-forward system for transferring E-mail between systems using a periodic dial-up. It is very efficient because the transfer is automatic: it dials up, transfers mail, and shuts down the call immediately. This can happen at preset times, completely unattended. Furthermore, unlike POP, you can transfer E-mail for a whole domain or multiple domains at the same time. So if you have a uucp account for domain, all mail for will be routed to your system in one call, where it can be delivered into separate mailboxes.


uucp systems which dial up to each other are called "neighbours". For two machines A and B, they are neighbours if either A calls B, or B calls A. It doesn't matter who initiates the call - mail is still transferred in both directions.

uucp names

Every computer in a uucp network is identified by a uucp name. This consists of up to seven letters or numbers, and is unique within a particular uucp network, i.e. a group of machines which exchange mail via uucp. Longer names may work for some uucp implementations but not all, so it is safest to stick to seven or less, preferably all lower-case letters.

In the days before DNS, uucp names were used in E-mail addresses. Addresses were shown as "bang paths" showing the series of hosts you had to traverse to reach a particular destination: e.g.

means "send to computer uunet, who will send to computer apple, who will send to computer vox, who will send to the user named steve"

Modern systems use domain names instead, and the mail software, if configured properly, will take care of routing the message between systems. If a system doesn't have a domain name you can use the uucp name plus the fake domain ".uucp" - for example "vox.uucp" - but this address can't be used to receive mail from the Internet. It is much better to get a proper domain name allocated. Note that the domain name need not bear any resemblence to the uucp name you choose.

uucp spool directories

Since uucp is a store-and-forward system, messages are stored on each of the neighbours, and transferred when the dial-up happens. A machine has a spool directory (/var/spool/uucp/uucpname) for each of its neighbours; this is created automatically. The spool directory consists of a series of jobs to be executed on the remove machine; for E-mail the job is "rmail address", since rmail is the program which receives and processes incoming mail from uucp.

You can inspect the queues using uustat. Each message is identified with a job ID.

    uustat -a              <<Show all queued messages
    uustat -s uucpname     <<Show messages queued for the given system
    uustat -k jobid        <<Delete (kill) the given job

File transfer - uucico and uucp login accounts

The actual transfer of files is performed by the program 'uucico'. The sequence of operations when machine A calls up machine B is as follows:
  1. uucico is started on machine A. This can be done manually, or by another daemon (for example 'cron', which runs programs at fixed times)
  2. uucico dials the phone number for machine B
  3. Machine B answers the phone (using 'getty') and produces a login prompt.
  4. uucico on machine A sends a login name and password.
  5. This account has uucico as its login shell. Hence machine B starts running uucico.
  6. At this point, uucico is running on both machines. They exchange system names, then transfer files, and finally hang up.
So you can see that it is necessary to have a login account on machine B which starts uucico. You can do this using useradd if you have it:
    useradd -d /var/spool/uucppublic -s /usr/sbin/uucico Uvox
or manually add an entry to /etc/passwd:
    Uvox::547:100:Vox UUCP:/var/spool/uucppublic:/usr/sbin/uucico
where '547' is the first unused UID on your system. The account's home directory is /var/spool/uucppublic. (Slackware 3.1: use /usr/lib/uucp/uucico instead of /usr/sbin/uucico)

The login name (Uvox in this case) doesn't need to bear any resemblence to the uucp name, but it is conventional to use a capital 'U' plus the uucp name. By including a capital letter, this login account can't receive E-mail (i.e. nobody can send mail to Uvox@your.machine). You don't want this to happen because nobody would ever download the mail addressed to Uvox.

Of course, if machine A only ever calls machine B, then only machine B needs to have a login account.

uucp configuration files

There are several flavours of uucp. The version supplied with both Red Hat and Slackware Linux is called Taylor uucp, and it can be configured using two different types of configuration files: its own style ("Taylor") config files, and the standard "HDB" config files, named after the Honey-Dan-Beer version of uucp. Since HDB files are more widely used and understood, I will describe these.

Red Hat 4.1 users note: The file locations given are for the package uucp-1.06.1-10. If you have an earlier version of this package, you must upgrade, as it had some serious bugs which prevented uucp working at all. Use the package supplied with Red Hat 4.2.
Slackware 3.1 users note: You will need to make the following changes when reading the discussion below.
    /etc/uucp/            --> /var/lib/uucp/taylor_config/
    /etc/uucp/oldconfig/  --> /var/lib/uucp/hdb_config/
    /var/log/uucp/Log     --> /var/spool/uucp/.Log/uucico/*
    /var/log/uucp/Debug   --> /var/spool/uucp/.Admin/audit.local
    /var/log/uucp/Stats   --> /var/spool/uucp/.Admin/xferstats
    uuchk                 --> /usr/lib/uucp/uuchk
    uucico                --> /usr/lib/uucp/uucico

HDB configuration files are stored in the directory /etc/uucp/oldconfig/ and consist of the following files:

(note the initial capital letter). The Systems file may contain passwords used to dial out to other systems, so this file needs to be protected from read access except for the 'uucp' user and group. Red Hat takes care of this for you. Slackware users can do the following:
chown uucp.uucp /var/lib/uucp/
chmod 770 /var/lib/uucp/
You can check your configuration files with the following command:
    uuchk | less
which will report the location of any syntax errors if there are any, or give a verbose description of your system configuration if not.

You can also get a list of all your neighbours by typing 'uuname'.

Systems file

The Systems file contains an entry for each of your machine's neighbours. Here is an example:
sparky  Any   ACU 38400 7531234 ogin:--ogin: Utiger word: 01dcr0Ck
vox     Never
Here, we have two neighbours. "sparky" is the uucp name of a system we dial out to, and the rest of the line gives the parameters we need to call. "vox" is also a neighbour, but we never call them - so presumably, they must call us.

The fields of the System file are as follows:

The uucp name of our neighbour
The times we may dial up to them. This field can be used to limit dial-out to evenings only, for example. Put "Never" for machines which always call us.
These two fields identify an entry in the Devices file, used when dialing out to this system.
The telephone number to call
ogin:--ogin: Utiger word: 01dcr0Ck
A chat script. In this case, we wait for "ogin:". If we don't see it we send a [Return] and wait again. When we see it, we send "Utiger" (followed by Return), then wait for "word:", then send "01dcr0Ck" followed by Return. You obviously have to change 'Utiger' and '01dcr0Ck' to the actual account name and password you use to start uucico on the remote machine.
You can put more than one line in for the same neighbour, as long as they are adjacent to each other:
sparky  Any   ACU 38400 7531234 ogin:--ogin: Utiger word: 01dcr0Ck
sparky  Any   ACU 38400 7531234 ogin:--ogin: Utiger word: 01dcr0Ck
sparky  Any   ACU 38400 2264322 ogin:--ogin: Utiger word: 01dcr0Ck
This means that uucico will try the number 7531234, if it fails try 7531234 again, and then try 2264322. So you have a way of automatically trying an alternative number if the main number is unavailable.

Permissions file

The Permissions file gives restrictions on what each neighbour is able to do on your system. In particular, it specifies which login name this machine must have used to log in. Since uucico just exchanges system names and has no other way of telling whether the remote machine is who they say they are, without this protection one of your neighbours could dial in and collect mail which was queued for another neighbour!

In the Permissions file, you can also set the uucp name by which your system is known to each neighbour. If you don't specify one, your host name is used - e.g. if your machine is then your uucp name is 'darkstar', so this is what your neighbour has to have in their Systems file. But by putting MYNAME=xxx you can override this individually for each of your neighbours.

You can split entries in the Permissions file by putting a '\' at the end of each line except the last. The above example says that uucp neighbour 'ccc' must log in using account Uccc, that they know our uucp name as 'tiger', that the remote site may request file transfers to and from the /var/spool/uucppublic directory, and that they may execute /usr/bin/rmail on our machine.

If you dial out to this machine, you will need an entry like this:

MACHINE=ccc MYNAME=tiger REQUEST=yes COMMANDS=/usr/bin/rmail
If you don't put an entry in your Permissions file for a machine, anybody will be able to collect that machine's mail. You will see this if you check your config files with uuchk.

Devices file

The Devices file lists the modem lines which can be referred to by your Systems file. For each modem line you give a reference to a script in the Dialers file which is used to send the appropriate AT command string. Here is an example Devices file:
ACU cua0 - 38400 usr
ACU cua1 - 38400 usr
ACU cua2 - 38400 telebit
TCP uucp - -
Entries in the Systems file which contain "ACU 38400" will match the first three lines. When dialling out, uucico will use the first one which is available. Lines cua0 and cua1 use the "usr" entry in the Dialers file, and line cua2 uses the "telebit" entry. The final "TCP" line is used if you want to run uucp over TCP/IP, which we will see later.

Dialers file

Finally, the Dialers file contains the chat scripts to send dialing commands to your modem and establish the link, before the chat script in the Systems file is used to issue the username and password. Here is a sample file:
usr	=W-,	"" ATM0DT\T CONNECT
telebit	=W-,	"" \rAT OK-AT-OK ATS11=100DT\T CONNECT
The first field is the name of the Dialer, as referred to in the Dialers file. The second field gives character translation: in this case we translate '=' in the phone number to 'W' and '-' to ','. The purpose of this is so that your phone numbers can contain '-' where you need a pause in the dialing sequence, and '=' where you want to wait for a new dial tone; these characters then get translated to the appropriate characters for your modem, which are normally ',' and 'W'. e.g.
   Phone number in Systems file:      9=123-4567
   Phone number sent to modem:        9W123,4567
The final field is the chat script for dialing to the modem, and this is what you will have to customise for your type of modem. It takes the form of an expect send expect send... sequence. Where you put '\T' in a send string, it is substituted with the phone number from the Systems file. Send strings automatically have a [return] character appended, unless you put '\c' at the end of the string.

Configure sendmail

Although you are now ready to place a call with uucico, this won't be useful until you have also configured your mail software to send outgoing mail and process any mail received via uucp. Here I will show how to configure 'sendmail' to run with uucp. You can also use 'smail' which is arguably easier to configure, as long as it has been compiled with the appropriate defaults; but the version of 'smail' in Slackware 3.1 is out of date and doesn't run with 2.0.x kernels, and Red Hat doesn't come with it at all.

sendmail is a complex program, and its configuration file /etc/ is extremely cryptic. But fortunately there is a set of configuration modules available, which you can string together using the 'm4' macro processing language to make a customised with very little effort.

You can find a full description of the m4 configuration options in file /usr/lib/sendmail-cf/README, but here I will give you some configurations you can use immediately. In each case you must create the file in /usr/lib/sendmail-cf/cf, and give it a name ending ".mc". This is then built into a config file ending ".cf" in /usr/lib/sendmail-cf/cf/obj, which you will later copy to /etc/ (For Slackware 3.1: each time you see /usr/lib/sendmail-cf/ replace it with /usr/src/sendmail/cf/)

Here is a sample .mc file which will route all outgoing mail to one uucp neighbour, presumably your ISP. In this case I am assuming its uucp name is "sparky".

dnl A config file which forwards all non-local mail to our smart host
VERSIONID(`linux uucp to smarthost')

If you want to add comments in this file, put 'dnl' in front of them (this is the m4 command to 'delete to end of line') so that they don't get passed through to the final file.

The main elements of this file are:

So you need to create this file in the correct directory, then compile it, like this.

    cd /usr/lib/sendmail-cf/cf (Red Hat 4.1)
or  cd /usr/src/sendmail/cf/cf (Slackware 3.1)
If the 'pmake' line doesn't work for any reason, use this instead:
    m4 ../m4/cf.m4 > obj/
Note that you must have the 'm4' package installed for this to work. The resulting .cf file is stored in /usr/lib/sendmail-cf/cf/obj/

Finally, you must create a file '/etc/'. This file contains all the host names by which this computer is known, in other words, all domains which are to be considered 'local' to this machine. You don't have to list the machine's full name (as shown if you type 'hostname -f') because it knows that already. However if there are alternative names by which your machine is known to the outside world, you must list them in /etc/ Even if there are no extra names, you need to create an empty file with this name.

The most common use of /etc/ is if your machine is called (let's say) "" but you also wish to receive mail for the domain "". In other words, the address "" is really the same as "". In this case, the machine knows that is its own name, but you need to add to /etc/ - otherwise, it would think that mail to this address is external, and try to forward it to another machine.

If you are going to use this trick, which helps keep E-mail addresses short and hides the internal setup of your domain, you need to arrange that mail to is actually delivered to machine This is achieved by putting an MX record for, pointing to, in the DNS. This can be done by whoever runs the DNS for your domain.

Test and install your

Before you install your new .cf file as /etc/, you can test it like this:
sendmail -v -C/usr/lib/sendmail-cf/cf/obj/ address
Now type some text
This will deliver the message to the given address, and display its progress on the screen. If everything seems OK, you can then install your new .cf file as /etc/, remembering to keep the old one as a backup!
    cd /etc
    cp /usr/lib/sendmail-cf/cf/obj/
Finally, you will need to locate the sendmail daemon, and send it a 'hup' signal (-1) to get it to reread its configuration files.
ps -axw | grep sendmail
   94  ?  S     0:00 sendmail: accepting connections on port 25
kill -1 94

Red Hat 4.1 note: This doesn't work properly because sendmail doesn't know how to restart itself. You will have to kill it and restart it again, like this:
kill 94                       # or whatever pid sendmail is
/usr/sbin/sendmail -bd -q1h
Alternatively you can fix the problem by editing /etc/rc.d/init.d/sendmail.init and changing the line which starts up the sendmail daemon, so that it includes the full pathname (/usr/sbin/sendmail):
	echo -n "Starting sendmail: "
	daemon /usr/sbin/sendmail -bd -q1h

Checking outgoing mail

Now you have configured sendmail, you can try to send some mail to an Internet address, using pine or elm or your favourite mail program. The message should be queued for your uucp smarthost, and you can check this using uustat:
    uustat -s sparky
(assuming your smarthost's uucp name is "sparky"). You should also check that mail is delivered to local accounts on your system, for addresses like "". If your machine is known by more than one name, try them all.

Placing a call

Once you have configured uucp, and the other end is ready for your call (i.e. they have created a uucico login account and put you in their Systems file), you can place a call manually like this:
    uucico -S uucpname -x 3
The '-x 3' enables debugging at level 3. The uucico program will turn itself into a daemon and return you to the command prompt, but will run in the background. You can see its debugging messages like this:
    tail -f /var/log/uucp/Debug
since the 'tail -f' command shows you the last 10 lines of a file, plus any new lines as they are added. Hit Ctrl-C to get out of this.

Even if you place a call without debugging enabled, you will see entries created in /var/log/uucp/Log summarising each call in or out, and /var/log/uucp/Stats which shows how fast each file transfer was.

Processing incoming mail

Once the uucico session is complete, the 'uuxqt' daemon is automatically run, which processes any received files. Generally these will invoke 'rmail' to request delivery of the messages. For efficiency, the version of 'rmail' which comes with sendmail doesn't actually deliver the messages - it just puts them in sendmail's queue, which you can view by typing mailq. Normally sendmail checks its queue every hour, but you can force it to process waiting mail by typing sendmail -q

Typically, you would like your incoming mail processed quickly. One way to achieve this is by writing a script to dial out:

uucico -D -S sparky -x 3
sleep 10
sendmail -q
If you save this file as (for example) /usr/local/sbin/poll, and make it executable by "chmod +x /usr/local/sbin/poll", then typing "poll" will execute the series of commands given. The -D flag to uucico prevents it from going into the background, so the script will wait until uucico finishes, then wait another 10 seconds, then make sendmail process any queued mail.

Dialing out at preset times

Once your machine is successfully dialling out, you can set up your machine to dial out automatically at fixed times. The daemon which does this is called 'cron', and its configuration file a 'crontab'. Each user on the system has their own crontab. You can create or edit a crontab for user 'uucp' like this:
    crontab -u uucp -e (Red Hat 4.1)
    crontab -e uucp (Slackware 3.1)
This will put you into vi. If you want to use a sensible editor, create the crontab using joe and then install it from that file:
    crontab -u uucp -l >tempfile
    joe tempfile
    crontab -u uucp tempfile
Lines in crontab consist of the following fields: In each field, "*" matches anything. So the following example will run uucico to call system 'sparky' at 03:30, 09:30, 12:30 and 15:30, every Monday to Friday:
30 3,9,12,15 * * 1-5  /usr/sbin/uucico -s sparky
If you have written a poll script you can run that instead.

Red Hat has a more powerful cron daemon which can also read in entries from a global file /etc/crontab. This is in the same format as above, but has an extra field on each line, giving the username to run the process as. You may find this an easier place to put your crontab entries.

30 3,9,12,15 * * 1-5  uucp  /usr/sbin/uucico -s sparky

A more advanced sendmail configuration

The previous example routes all outgoing mail, except messages for users on the local system, to a smart host. However if you are providing uucp service for other sites, or you have some machines on your network which can receive mail via direct SMTP connections, you need to add some 'intelligence' to the mail routing. You can create a table of domains and destinations, called a 'mailertable'. First you need to add an extra FEATURE(mailertable) line to your config file, and rebuild /etc/ as described above:
VERSIONID(`linux uucp with mailertable')
define(`ConfSMTP_LOGIN_MSG',`$j Sendmail $b')

(The 'ConfSMTP_LOGIN_MSG' line tells sendmail NOT to give its version number when someone connects to your SMTP server. This prevents giving away some information which could be of interest to a hacker, especially if a security hole is discovered in the version of sendmail which you are running)

Next you need to create /etc/mailertable. Each line consists of:

Here is an example. Let's say we are ''. Mail sent to '' and '' should be sent using SMTP over our local area network; mail to any other address ending should be bounced straight back to sender, because we know no other machines exist in our domain. We also provide uucp service to a site whose domain name is '' and whose uucp name is 'minf'. All other mail needs to be forwarded to our smarthost.

In this case, /etc/mailertable would look like this:           error:error Unknown host      uucp-dom:minf
The "" line catches all addresses ending in apart from the specific ones listed, and the "error" delivery agent bounces the message back to the sender, with the message you give on the line. We don't list the smart host here - this is still in the .mc configuration file as before.

Before sendmail can use this file, you must compile it into a database format which is efficient to search:

    makemap hash /etc/mailertable < /etc/mailertable
If this doesn't work (and unfortunately 'makemap' has some problems in Slackware 3.1) you can replace 'hash' with 'btree' or 'dbm' which are two different database formats. You will also need to change the FEATURE(mailertable) line in your .mc file too, and recompile it:
FEATURE(mailertable,`btree -o /etc/mailertable')

Transferring files with uucp

As well as transferring E-mail messages to process with 'rmail', uucp can transfer raw files between neighbours. This is occasionally useful. Generally the permissions are set up so that you can only read or create files which are in /var/spool/uucppublic on the remote machine. To fetch a file from the remote machine, the syntax is this:
    uucp remote\!/var/spool/uucppublic/filename localfilename
To transfer a file from your machine to the remote:
    uucp localfilename remote\!/var/spool/uucppublic/filename
Note the syntax uucpname\!filename; the backslash is needed to stop the shell treating the exclamation mark specially. Now that most E-mail packages are able to send binary attachments using MIME, this facility of uucp is rarely used.

It is possible to run a uucp transfer over a TCP/IP connection. This is useful if your site has intermittent IP connectivity (e.g. via a dial-up PPP link) and you want to transfer uucp mail at the same time as using the Internet. It is also useful if you have a dial-up IP access point nearby, but your uucp mail host is far away, since you can save the cost of a long-distance phone call.

uucp over TCP/IP conventionally uses TCP port 540. To configure your machine to making outgoing connections over TCP/IP, you need to add a line to the Devices file:

    TCP uucp - -
There should already be a line in /etc/services which maps "uucp" to port 540/tcp. Then you add an entry into your Systems file which uses "TCP" instead of "ACU" for the dialer, a "-" for the speed, and the host name instead of the phone number:
sparky  Any   TCP   - ogin:--ogin: Utiger word: 01dcr0Ck
sparky  Any   ACU 38400 7531234       ogin:--ogin: Utiger word: 01dcr0Ck
In this case, if you run uucico to connect to system 'sparky', uucico will first try to establish a TCP connection to host "" (which is that machine's full hostname on the Internet). If it fails, it will then try to place a direct phonecall instead.

If you want to accept incoming connections over TCP/IP, you have to add the remote machine's username and password into a separate file, /etc/uucp/passwd

This is because uucico, when running as a TCP/IP daemon, generates its own username and password prompt, and doesn't check the /etc/passwd file. Since the passwords in the above file are unencrypted, it is very important to make sure it not readable by anyone apart from 'uucp'.

You also need to uncomment the following line in /etc/inetd.conf:

uucp  stream  tcp  nowait  uucp  /usr/sbin/tcpd  /usr/sbin/uucico -l
and send a HUP signal to inetd to make it reread this file:
killall -1 inetd

Taylor configuration files

As an alternative to HDB, Taylor uucp has its own configuration files. Whilst not necessarily any easier to write than HDB files, they are much more flexible and allow you to change parameters such as timeouts which you can't change using the older files.

Here is an example configuration:

# This is our uucp name
nodename tiger
# A system we connect to using uucp over TCP/IP
system ucb
call-login Utiger
call-password wibbly
time any
port type tcp

# We dial out to this system, which knows us as 'ccc'
system sparky
myname ccc
call-login Utiger
call-password 01dcr0Ck
time any
port usrobotics
phone 12345
# The far end supports large packet sizes so let's use them
# (greatly improves performance for calls routed via satellite)
protocol-parameter g retries 10
protocol-parameter g packet-size 1024

# This system dials into us
system vox
called-login Uvox
port usrobotics
type modem
device /dev/cua0
dialer hayes
speed 38400
dialer hayes
chat "" ATZ\r\d\c OK ATDT\T CONNECT
chat-fail BUSY
chat-fail NO\sCARRIER
There are many sensible defaults compiled in (notice that no login chat script is given, because the default is fine). If you are only doing uucp over TCP/IP, you can leave out the 'port' and 'dial' files entirely.

Collecting pop3 mail

Red Hat Linux includes a utility called 'fetchmail' which can be used to retrieve mail from a remote POP3 server and deposit it on your local server. By default it delivers mail by opening an SMTP connection on port 25, which assumes that sendmail is already running as a daemon on your machine.

Using fetchmail is very easy. Create a file .fetchmailrc in your home directory:

poll <server> proto <protocol> user <remote-username> is <local-username>
You must make this file unreadable (chmod 600 .fetchmailrc). For example:
poll proto pop3 user corocom is jan
Then when you type 'fetchmail', mail for user 'corocom' on server '' will be collected using pop3 and delivered to user 'jan' on the local machine.

You can include your password in this file too, to completely automate the process - but beware the security implications, since the root user is able to read everybody's .fetchmailrc file.

You can put entries for multiple POP3 accounts in the same configuration file, you can choose to keep your mail on the remote server, and you can also run fetchmail as a daemon (so it checks for new mail periodically). For more information see 'man fetchmail'.

Last updated 14 June 1998