Cyrus
Contents
- 1 Syntax
- 2 imapd.conf configuration options
- 3 Notes on Cyrus build
- 4 Listing and fixing mailbox quotas (both use and limit)
- 5 Deleting a mailbox
- 6 Renaming a mailbox
- 7 Error: can't fork process to run service Resource temporarily unavailable
- 8 MUPDATE/IMAP administration
- 9 Migration from dovecot
- 10 Assorted Links
Syntax
Syntax used in this document includes the following.
- example.com - a domain name
- username - a username or local part of an email address
- cyradm> - a cyradm prompt (already authenticated as an admin user) - usually displayed as localhost.localdomain>
- cyrus$ - shell prompt for the cyrus user (in some cases you can also do the command using su cyrus -c "..." but be careful to correctly escape characters)
- root# - shell prompt for the root user
imapd.conf configuration options
The example commands given are for installations where the imapd.conf has the following options (among others)
admins: cyrusadmin defaultdomain: cyrusdomain allowusermoves: on deletedprefix: DELETED delete_mode: delayed expunge_mode: delayed unixhierarchysep: on virtdomains: userid hashimapspool: true fulldirhash: on
Notes on Cyrus build
# /etc/init.d/cyrus-imapd start
This will spawn listeners for those services listed in /etc/cyrus.conf - typically POP3S, POP3, IMAPS, and IMAP.
Basic IMAP functionality can be tested:
# /usr/lib/cyrus-imapd/imtest -a user@domain -w password
This should print the server capabilities and end up saying:
Authenticated. Security strength factor: 0
Cyrus may need an extra entry in /etc/services if you're planning to use a murder (group of cyrus backends/frontends).
mupdate 3905/tcp # Cyrus mupdate
Sieve port on CentOS 6
The default port number for sieve on CentOS 6 has changed. If working in a mixed CentOS 5 / CentOS 6 environment, ensure that the port number is standardised to avoid strange problems connecting to sieve.
# grep sieve /etc/services sieve 2000/tcp # Sieve Mail Filter Daemon sieve 2000/udp # Sieve Mail Filter Daemon
# grep sieve /etc/services sieve-filter 2000/tcp # Sieve Mail Filter Daemon sieve-filter 2000/udp # Sieve Mail Filter Daemon sieve 4190/tcp # ManageSieve Protocol
Edit /etc/services so that it's consistently either like the top one or bottom. If using the bottom one, ensure the bottom line is commented out so there's nothing on port 4190.
Listing and fixing mailbox quotas (both use and limit)
Check mailbox quota use for the domain example.com
cyrus$ /usr/lib/cyrus-imapd/quota -d example.com
To check and fix the mailbox quota use for the domain example.com
cyrus$ /usr/lib/cyrus-imapd/quota -d example.com -f
If a mailbox quota is incorrect on the mailstore it can be changed from cyradm. The below example sets the quota to 40MB (the number is the mailbox quota in KB)
cyradm> setquota user/username@example.com 40960
To view the current quota for a mailbox
cyradm> listquota user/username@example.com
Deleting a mailbox
$ cyradm -u adminuser localhost
localhost.localdomain> setacl user/username@example.com adminuser all localhost.localdomain> deletemailbox user/username@example.com
Renaming a mailbox
In this example, all mailboxes at example.net need to be renamed to example.com - any subfolders can be renamed manually, or you can just do the top level INBOX and all the subfolders will also be renamed.
$ cyradm -u adminuser localhost
cyradm> renamemailbox user/bob@example.net user/bob@example.com cyradm> renamemailbox user/info@example.net user/info@example.com
NOTE - if renaming a mailbox or folder with a single quote (') in the name, you will need to escape it.
localhost> renamemailbox user/mick^o\'brian@example.org user/mick^o\'brian@example.com
If you are renaming or working with folders with spaces, you can either escape the spaces or put double quotes (") around the mailbox
localhost> renamemailbox "user/me/My Folder@example.org" user/me/MyFolder@example.org localhost> renamemailbox user/me/My\ Folder@example.org user/me/MyFolder@example.org
This is when the number of files/processes that cyrus is using has exceeded the ulimit variables.
To fix, add the following into /etc/security/limits.d/90-nproc.conf
cyrus soft nproc unlimited cyrus hard nproc unlimited cyrus soft nofile 30000 cyrus hard nofile 30000
And then reboot the server (can we just do this instead? service cyrus-imapd stop ; service cyrus-imapd start)
MUPDATE/IMAP administration
In the event of broken mailboxes, there are a number of things that can be done by poking directly at the mupdate or imap servers. Using the mupdatetest program, you can query and modify the central database directly. Note the format of mailbox names is domain.com!user.user^name where the dots in the user part of the email address are replaced with ^
RFC for MUPDATE protocol - http://tools.ietf.org/html/rfc3656
MUPDATE
Connecting to the mupdate server is similar to connecting to the IMAP server.
root# mupdatetest -a cyrusadmin mupdatehost
MUPDATE - FIND
Query the mupdate server to see if a mailbox exists
mupdate> F01 FIND "example.com!user.username" F01 MAILBOX {25+} example.com!user.username {26+} mailstore1.example.net!fs1 {20+} username@example.com F01 OK "Search completed"
MUPDATE - DELETE
Delete a mailbox
mupdate> D01 DELETE "example.com!user.username" D01 OK "done"
MUPDATE - ACTIVATE
Create a mailbox (note this doesn't actually create it on the backend server, just within the mupdate server)
mupdate> A01 ACTIVATE "example.com!user.username" "mailstore1.example.net!fs1" "username@example.com lrswipkxtecda" A01 OK "done"
IMAP
To create the folder, you need to login to the cyrusbe server where the mailbox needs to reside and run the following - this part is the IMAP server, not the MUPDATE server. It may also remove the need for the above ACTIVATE command to be run.
imtest -a cyrusadmin localhost
IMAP - GETANNOTATION
This command can be used to fetch the amount of space left on the partition.
0 GETANNOTATION "" "*" "value.shared" * ANNOTATION "" "/vendor/cmu/cyrus-imapd/freespace" ("value.shared" "107410772") 0 OK Completed
The value returned is in KB. This is the same information as the following (but in a raw form).
cyradm> info Server Wide: freespace: 107410772
IMAP - LOCALCREATE
This command causes the IMAP server to create a local folder. If there is a folder name rather than just INBOX, the folder name is inserted just before the @ i.e user/username/folder@example.com
LC1 LOCALCREATE user/username@example.com LC1 OK Completed
It can also be written on a single line.
LC1 LOCALCREATE user/username@'example.com
IMAP - SETACL
Next we have to set permissions on the newly created folder so that the user can access it.
ACL0 SETACL user/username@example.com username@example.com lrswipkxtea ACL0 OK Completed
IMAP - MUPDATEPUSH
And finally we push the details to the mupdate server so that everything syncs up properly.
MP1 MUPDATEPUSH user/username@example.com MP1 OK Completed
IMAP - LOCALDELETE
To remove a folder locally:
LD1 LOCALDELETE user/username@example.com LD1 OK Completed
IMAP - Other commands
Basic IMAP commands. All commands must be prefixed with an identifier, just a string that will match the response to the command. Typically for manual interaction, it's sufficient to just use a single character - in the following examples, I'll use "A". Data sent to the server will be marked with ">>" and data received will be marked using "<<" followed by the prefix "A"
You can use imtest or telnet to do these commands. Note that imtest will perform the initial login for you.
Logging in
>> A LOGIN username password
<< A OK [CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE ACL RIGHTS=kxte QUOTA MAILBOX-REFERRALS NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE LIST-EXTENDED WITHIN QRESYNC SCAN XLIST URLAUTH URLAUTH=BINARY X-NETSCAPE LOGINDISABLED COMPRESS=DEFLATE IDLE] User logged in SESSIONID=<bocks.com-15513-1374369517-1>
In this instance I've used a plaintext password, but I think this may vary depending on server settings (it's always worked for me so far though). It might have something to do with the imapd.conf setting "allowplaintext:on"
Opening a folder
>> A SELECT INBOX
<< * 673 EXISTS << * 0 RECENT << * FLAGS (\Answered \Flagged \Draft \Deleted \Seen $NotJunk NotJunk $Junk) << * OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen $NotJunk NotJunk $Junk \*)] Ok << * OK [UNSEEN 33] Ok << * OK [UIDVALIDITY 1374358277] Ok << * OK [UIDNEXT 675] Ok << * OK [HIGHESTMODSEQ 677] Ok << * OK [URLMECH INTERNAL] Ok << A OK [READ-WRITE] Completed
If you want to know what the response means, go read the documentation. An "OK" as the last line is a good sign though.
Reading a message
If you only know the UID, you have to convert it to a message id that the IMAP server will understand before you can read it.
>> A SEARCH UID 100
<< * SEARCH 99 << A OK Completed (1 msgs in 0.000 secs)
This means that if we want to read the UID '100' you have to fetch 99 instead. Not sure why this happens, but I suspect it's because you'll get missing messages eventually as older ones are deleted and the message id is simply a sequential number.
In the above example, a little investigation reveals UID 1 to be missing.
>> A SEARCH UID 1
<< * SEARCH << A OK Completed (0 msgs in 0.000 secs)
UID 1 is missing.
>> A SEARCH UID 2
<< * SEARCH 1 << A OK Completed (1 msgs in 0.000 secs)
UID 2 returns message id 1
Next step is to actually fetch the message
>> A FETCH 99 FULL
<< * 99 FETCH (FLAGS (\Deleted \Seen) INTERNALDATE " 6-Jul-2013 04:02:12 +0100" RFC822.SIZE 5998 ENVELOPE ("Sat, 06 Jul 2013 04:02:12 +0100" "Logwatch for wood.bocks.com (Linux)" ((NIL NIL "logwatch" "wood.bocks.com")) ((NIL NIL "logwatch" "wood.bocks.com")) ((NIL NIL "logwatch" "wood.bocks.com")) ((NIL NIL "root" "wood.bocks.com")) NIL NIL NIL "<E1UvIlB-0004xH-U4@wood.bocks.com>") BODY ("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "7BIT" 5406 174)) A OK Completed (0.000 sec)
This provides some of the headers and the body part specifies something useful if you happen to speak IMAP! Next we'll just fetch the whole message content in an easy to read format.
>> A FETCH 99 BODY[]
<< * 99 FETCH (BODY[] {5998} Return-path: <root@wood.bocks.com> Envelope-to: root@wood.bocks.com ... ) A OK Completed (0.000 sec)
The final ) is to match the one before BODY[] on the first line. I believe the 5998 is the number of bytes that follows.
Logging out (nicely)
Obviously you could just terminate the connection, but the better way is to logout nicely.
>> A LOGOUT
<< * BYE LOGOUT received << A OK Completed
At this point the connection is closed and you should be returned to a shell prompt.
Migration from dovecot
Because dovecot (configured to use mbox + /var/spool/mail/$USER) allows all kinds of extra characters in folder names, you may experience some issues migrating to cyrus. I found the best way was to setup cyrus on a separate port number and use imapsync with the following options:
# imapsync \ --pidfile /tmp/${USERNAME}-imapsync.pid \ --host1 127.0.0.1 \ --host2 127.0.0.1 \ --user1 $USERNAME \ --user2 $USERNAME \ --port1 143 \ --port2 1143 \ --delete2 \ --nofoldersizes \ --noreleasecheck \ --subscribe_all \ --password1 "$PASSWORD" \ --password2 "$PASSWORD" \ --regextrans2 's/[\(\)\!]/~/g'
The last one is the one that strips out ( ) and ! from folder names and replaces them with ~ instead. For the most part, this seemed to fix folders with bad names. You'll know you have them because without the last line you'll get errors like this appearing in the imapsync output.
Couldn't create folder [INBOX/!!Replies!!] from [!!Replies!!]: 8 NO Invalid mailbox name
If you also get errors saying the following error (typically in Sent Items), you can add "--addheader" to the options above to fix it by adding its own Message-Id if it's missing.
Host1 uid 6 no header by parse_headers so taking whole header with BODY.PEEK[HEADER] Host1 Sent Items/6 size 1633 ignored (no wanted headers so we ignore this message)
With --addheader it says this instead.
Host1 uid 6 no header by parse_headers so taking whole header with BODY.PEEK[HEADER] Host1 uid 6 no header found so adding our own [Message-Id: <6@imapsync>]