The Dovecot 2.1 LMTP server currently always strips the address extension
from a recipient address (if recipient_delimiter is set), meaning user IDs
cannot contain the recipient delimiter character, e.g. "user+foo" is not
supported.
This was surprising for me, as Postfix behaves differently in this regard:
It first looks up "user+foo", and only then "user".
The attached patch works for me and brings Dovecot's behavior in line with
Postfix. Please let me know what you think about it.
diff -r 1ab8e0e699f7 src/lmtp/commands.c
--- a/src/lmtp/commands.c Wed Jan 09 07:01:41 2013 +0200
+++ b/src/lmtp/commands.c Sat Jan 12 17:25:27 2013 +0100
@@ -480,12 +480,39 @@
return ret;
}
+static int rcpt_user_lookup(struct client *client, struct mail_recipient *rcpt,
+ const char *username)
+{
+ struct mail_storage_service_input input;
+ const char *prefix;
+ const char *error = NULL;
+ int ret;
+
+ memset(&input, 0, sizeof(input));
+ input.module = input.service = "lmtp";
+ input.username = username;
+ input.local_ip = client->local_ip;
+ input.remote_ip = client->remote_ip;
+ input.local_port = client->local_port;
+ input.remote_port = client->remote_port;
+
+ ret = mail_storage_service_lookup(storage_service, &input,
+ &rcpt->service_user, &error);
+
+ if (ret < 0) {
+ prefix = t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL_PREFIX,
+ username);
+ client_send_line(client, "%s%s", prefix, error);
+ return -1;
+ }
+
+ return ret;
+}
+
int cmd_rcpt(struct client *client, const char *args)
{
struct mail_recipient rcpt;
- struct mail_storage_service_input input;
- const char *address, *username, *detail, *prefix;
- const char *error = NULL;
+ const char *address, *username, *detail;
int ret = 0;
client->state.name = "RCPT TO";
@@ -508,36 +535,34 @@
client_send_line(client, "501 5.5.4 Unsupported options");
return 0;
}
- rcpt_address_parse(client, address, &username, &detail);
if (client->lmtp_set->lmtp_proxy) {
+ rcpt_address_parse(client, address, &username, &detail);
if (client_proxy_rcpt(client, address, username, detail))
return 0;
}
- memset(&input, 0, sizeof(input));
- input.module = input.service = "lmtp";
- input.username = username;
- input.local_ip = client->local_ip;
- input.remote_ip = client->remote_ip;
- input.local_port = client->local_port;
- input.remote_port = client->remote_port;
-
- ret = mail_storage_service_lookup(storage_service, &input,
- &rcpt.service_user, &error);
-
- if (ret < 0) {
- prefix = t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL_PREFIX,
- username);
- client_send_line(client, "%s%s", prefix, error);
+ /* First, try looking up with the whole address as the username */
+ ret = rcpt_user_lookup(client, &rcpt, address);
+ if (ret > 0) {
+ username = address;
+ detail = "";
+ }
+ /* User not found, remove extension and try again */
+ if (ret == 0) {
+ rcpt_address_parse(client, address, &username, &detail);
+ /* Avoid second userdb lookup when unneccessary */
+ if (*detail != '\0')
+ ret = rcpt_user_lookup(client, &rcpt, username);
+ if (ret == 0) {
+ client_send_line(client,
+ "550 5.1.1 <%s> User doesn't exist: %s",
+ address, username);
+ return 0;
+ }
+ }
+ if (ret == -1)
return 0;
- }
- if (ret == 0) {
- client_send_line(client,
- "550 5.1.1 <%s> User doesn't exist: %s",
- address, username);
- return 0;
- }
if (client->proxy != NULL) {
/* NOTE: if this restriction is ever removed, we'll also need
to send different message bodies to local and proxy