Récupérer ses courriels en local avec getmail et dovecot

De Wiki de Romain RUDIGER
Aller à : navigation, rechercher

Introduction

L'idée est de centraliser ses différentes messageries électroniques en un point. Cette page détaille donc la configuration de getmail pour récupérer ses courriels et appliquer les filtres Sieve.

dovecot-2.1.7
dovecot-2.1-pigeonhole-0.3.1
getmail 4.27.0

Le script général

Ce script est utilisé en crontab de root pour récupérer les mails pour tous les utilisateurs (voir la variable USERLIST). Il gère les erreurs et les fichiers de logs.

/etc/dovecot/getmail-crontab.sh

 #!/bin/bash
# -*- coding: UTF8 -*-

# Script to get the mails of the user list
# The configuration is fetched from ~/.getmail/enable/


####
# FUNCTIONS

# Quit the script
function exit_script {
	exit $1
}

# Start user work
function start_user_work {
	Start_User_Date=$(get_date)
	Start_User_Time=$(date +%s)
}

# End user Work
function end_user_work {
	if [[ ! -z $Start_User_Time ]]; then
		Duration_Time=$(expr $(date +%s) - $Start_User_Time)
		Duration_Time_Mn=$(expr $Duration_Time / 60)
		Duration_Time_Sec=$(expr $Duration_Time - \( $Duration_Time_Mn \* 60 \) )
		if [[ -z ${Log} ]]; then
			info_nolog "Duration time: ${Duration_Time_Mn}m ${Duration_Time_Sec}s"
			info_nolog "Return code: $1"
		else
			info "Duration time: ${Duration_Time_Mn}m ${Duration_Time_Sec}s"
			info "Return code: $1"
			info "Log file: ${Log}"
		fi
		if [[ $1 -ne 0 && -z $NoMail ]]; then
			mail -s "Error while fetching your mails" $username <<EOM
Hello,
An error was found while fetching your mails, please review the log and fix the error.
--------------------------------------------------------------------------------------
$(cat $Log)
EOM
		fi
	fi
}

# Catch kill of the script
function handle_trap
{
   if [[ -z ${Log} ]]; then
      error_nolog "This script have been killed by an user ($1)!"
   else
      error "This script have been killed by an user ($1)!"
   fi
   exit_script 1
}
trap "handle_trap SIGTERM" SIGINT SIGTERM

# Usage
function usage {
	echo "Usage: ${Program}"
	echo "   [-options]	: add options to getmail."
	echo "   [-nomail]	: don't send a mail if we have trouble to fetch a mail box."
	exit_script 1
}

# Get date
#
function get_date
{
   echo $(date +%Y%m%d-%H%M)
}

# Display and write in log an ERROR message
#
# Arg : <message description>
#
# Exemple : error "Can't create the file."
function error
{
   echo -e "ERROR-$(get_date)-$(hostname)-$1"
   [[ -n ${Log} ]] && echo -e "ERROR-$(get_date)-$(hostname)-$1" >> ${Log}
}

# Display and write in log an INFO message
#
# Arg : <message description>
#
# Exemple : info "Start of the script..."
function info
{
   echo -e "INFO-$(get_date)-$(hostname)-$1"
   [[ -n ${Log} ]] && echo -e "INFO-$(get_date)-$(hostname)-$1" >> ${Log}
}

# Display and write in log a WARNING message
#
# Arg : <message description>
#
# Exemple : warning "Be aware, the dump may be incomplete!"
function warning
{
   echo -e "WARNING-$(get_date)-$(hostname)-$1"
   [[ -n ${Log} ]] && echo -e "WARNING-$(get_date)-$(hostname)-$1" >> ${Log}
}

# Check the last return code, display a message and do somethnig
#
# Arg : <message description> [return code (0)*] [action if the return code is different (exit_script 1)*]
# *=default value
#
# Exemple : check_cmd "Error, the last command failed." 0 "exit_script 5"
function check_cmd
{
   return_code=$?
   [[ -z $2 ]] && code_retour=0 || code_retour=$2
   [[ -z $3 ]] && action="exit_script 1" || action="$3"
   [[ ${return_code} -ne ${code_retour} ]] && { error "$1"; ${action}; }
} 

# Check a regular expression
#
# Args : <value to test> <regexp>
#
# Exemple : test_regExp $VAR "^([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}$"
#  check if $VAR is an IPv4 address, return 0 if ok.
function test_regExp
{
	echo "$1" | /bin/grep -Eq "$2" > /dev/null
	return $?
}

####
# Main code

# Fixed options
USERLIST=""
GETMAIL_BIN=/usr/local/bin/getmail
GETMAIL_CONF_DIR_VAR=/home/-username-/.getmail/enable
GETMAIL_LOG_DIR_VAR=/home/-username-/.getmail/log/

# default options value
Program=$(basename $0)
Program_dir=$(dirname $0)
LogRetention=2
NoMail=
Options=
Error=

# read the arguments
for arg in $@; do
	argVal=$(echo $arg | awk -F = '{print $2}')
	if [[ "$arg" == "-help" ]]; then
		usage
	fi
	if [[ "$arg" == "--help" ]]; then
		usage
	fi
	if [[ $(test_regExp "$arg" "^-nomail$" ; echo $?) -eq 0 ]]; then
		NoMail=true
		continue
	       
	fi
	if [[ $(test_regExp "$arg" "^-options=.*$" ; echo $?) -eq 0 ]]; then
		Options=$argVal
		continue
	fi
	error "Unknow or invalid argumenent: $arg"
	usage       
done       

# For each user
for username in $USERLIST; do
	id $username 1>/dev/null 2>&1
	   check_cmd "The username $username doesn't exist !"
	start_user_work
	# Replace username in the dir vars
	GETMAIL_CONF_DIR=$(echo $GETMAIL_CONF_DIR_VAR|sed "s/-username-/$username/")
	GETMAIL_LOG_DIR=$(echo $GETMAIL_LOG_DIR_VAR|sed "s/-username-/$username/")
	Log=$GETMAIL_LOG_DIR$(basename $0)-${Start_User_Date}.log
	# Create the log file with the user uid/gid and mask
	su - $username -c "touch $Log"
	# Check the dir
	[[ ! -d $GETMAIL_CONF_DIR ]] && error "The configuration dir must exist: $GETMAIL_CONF_DIR" && exit_script 1
	[[ ! -d $GETMAIL_LOG_DIR ]] && mkdir -p $GETMAIL_LOG_DIR
	[[ ! -d $GETMAIL_LOG_DIR ]] && error "Can't create the log dir: $GETMAIL_LOG_DIR" && exit_script 1
	# Check the getmail binary
	[ -x $GETMAIL_BIN ]
	check_cmd "$GETMAIL_BIN doesn't exist."

	# nettoyage des anciens log
	info "Clean up the log files"
	find $GETMAIL_LOG_DIR -type f -name "$(basename $0)-*.log" -mtime +$LogRetention -print -exec rm -f {} \; 2>&1 | tee -a $Log
       
	info "Get the mails with the configuration file(s) in $GETMAIL_CONF_DIR:"
	for file in $(ls -1 $GETMAIL_CONF_DIR); do
		info "Check the configuration file $file."
		su - $username -c "$GETMAIL_BIN -r $GETMAIL_CONF_DIR/$file --dump >/dev/null 2>&1"
		if [[ $? -ne 0 ]]; then
			error "Error found in the configuration:"
			su - $username -c "$GETMAIL_BIN -r $GETMAIL_CONF_DIR/$file --dump" 2>&1 | tee -a $Log
			Error=true
			continue
		fi
		info "Get the mail for the configuration file $file:"
		su - $username -c "$GETMAIL_BIN -r $GETMAIL_CONF_DIR/$file $Options" 2>&1 | tee -a $Log
		if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
			error "Error while fetching the mails for the configuration file $file."
			Error=true
			continue
		fi
	done
       
	# If the Error var is not null
	if [[ -n $Error ]]; then
		    end_user_work 1
	else
		    end_user_work 0
	fi
done

Le mettre en crontab toutes les minutes :

/usr/local/bin/hatimerun -t 55 /usr/local/bin/halockrun -nc /tmp/getmail-crontab.lock /etc/dovecot/getmail-crontab.sh 1>/dev/null 2>&1

Configuration utilisateur

Structure

Créer la structure des dossiers :

mkdir -p ~/.getmail/enable
chmod 700 ~/.getmail

Fichier de configuration

Il faut faire un fichier par boîte, par exemple :

vim ~/.getmail/bla@example.com-pop3
[retriever]
type = SimplePOP3SSLRetriever
server = example.com
port = 995
username = <utilisateur>
password = <mot de passe en clair>

[destination]
type = MDA_external
path = /usr/local/libexec/dovecot/deliver
arguments = ("-e",)

[options]
# Supprimer les message du serveur source si la reception reussi !
delete = true
# Ne marque pas les courriels comme recu (Received:)
received = false
# Ne marque pas les courriels comme delivre (Delivered-To:)
delivered_to = false
# Pour marquer ou non les courriels recus comme lus
read_all = false
# Niveau de detail des log (0=errors, 1=just received mails, 2=all actions)
verbose = 2

Voir la documentation de getmail pour les autres protocoles et options : documentation

Ajouter son username

Modifier le script qui se lance toutes les minutes pour ajouter son nom d'utilisateur '/etc/dovecot/getmail-crontab.sh' :

USERLIST="user1 user2 user3"

Créer un lien symbolique :

ln -s ~/.getmail/bla@example.com-pop3 ~/.getmail/enable/bla@example.com-pop3

Problème de boîte

La boîte aux lettres demandé n'existe pas :

getmail version 4.27.0
Copyright (C) 1998-2009 Charles Cazabon.  Licensed under the GNU GPL version 2.
SimpleIMAPRetriever:romain@localhost:143:
oldmail file /home/romain/.getmail/oldmail-localhost-143-romain-.99-Refilter not found, reverting to /home/romain/.getmail/oldmail-localhost-143-romain
refilter: operation error (IMAP server failed to return correct SELECT response (invalid literal for int() with base 10: '[CANNOT] Invalid mailbox name'))
  0 messages (0 bytes) retrieved, 0 skipped
IMAP error during logout (command CLOSE illegal in state AUTH, only allowed in states SELECTED)

Problème d'authentification

Il faut vérifier votre nom d'utilisateur et le mot de passe :

getmail version 4.27.0
Copyright (C) 1998-2009 Charles Cazabon.  Licensed under the GNU GPL version 2.
SimplePOP3SSLRetriever:test@example.com@example.com:995:
test@example.com-pop3s: operation error (POP error (-ERR Authentication failed.))
  0 messages (0 bytes) retrieved, 0 skipped

Erreur dans le fichier de configuration

Configuration error: configuration file /home/romain/.getmail/enable/00-test@example.com-imaps incorrect (File contains parsing errors: /home/romain/.getmail/enable/00-test@example.com-imaps
        [line  9]: 'Error_Level\n')

Quand cela fonctionne

46 courriels :

getmail version 4.27.0
Copyright (C) 1998-2009 Charles Cazabon.  Licensed under the GNU GPL version 2.
SimplePOP3SSLRetriever:example@test.fr@pop.test.fr:995:
  msg  1/46 (35231 bytes) from <kk@lol.fr> delivered to MDA_external command deliver (), deleted
  msg  2/46 (100607 bytes) from <kk@lol.fr> delivered to MDA_external command deliver (), deleted
  msg  3/46 (7403 bytes) from <kk@lol.fr> delivered to MDA_external command deliver (), deleted
...
  46 messages (835232 bytes) retrieved, 0 skipped
Summary:
Retrieved 46 messages (835232 bytes) from SimplePOP3SSLRetriever:example@test.fr:995

0 courriel :

getmail version 4.27.0
Copyright (C) 1998-2009 Charles Cazabon.  Licensed under the GNU GPL version 2.
SimpleIMAPSSLRetriever:example@test.fr@pop.test.fr:993:
  0 messages (0 bytes) retrieved, 0 skipped

Documentation