dovecot-2.0: lib-lda: Added submission_host setting to send mail...
dovecot at dovecot.org
dovecot at dovecot.org
Tue Feb 22 13:57:30 EET 2011
details: http://hg.dovecot.org/dovecot-2.0/rev/be78b9fd88e7
changeset: 12617:be78b9fd88e7
user: Timo Sirainen <tss at iki.fi>
date: Tue Feb 22 13:57:20 2011 +0200
description:
lib-lda: Added submission_host setting to send mails via SMTP instead of sendmail.
diffstat:
doc/example-config/conf.d/15-lda.conf | 3 +
src/lib-lda/lda-settings.c | 2 +
src/lib-lda/lda-settings.h | 2 +
src/lib-lda/smtp-client.c | 196 ++++++++++++++++++++++++++++++++++++++-
4 files changed, 198 insertions(+), 5 deletions(-)
diffs (293 lines):
diff -r 3053befe6a64 -r be78b9fd88e7 doc/example-config/conf.d/15-lda.conf
--- a/doc/example-config/conf.d/15-lda.conf Tue Feb 22 11:59:57 2011 +0200
+++ b/doc/example-config/conf.d/15-lda.conf Tue Feb 22 13:57:20 2011 +0200
@@ -17,6 +17,9 @@
# Binary to use for sending mails.
#sendmail_path = /usr/sbin/sendmail
+# If non-empty, send mails via this SMTP host[:port] instead of sendmail.
+#submission_host =
+
# Subject: header to use for rejection mails. You can use the same variables
# as for rejection_reason below.
#rejection_subject = Rejected: %s
diff -r 3053befe6a64 -r be78b9fd88e7 src/lib-lda/lda-settings.c
--- a/src/lib-lda/lda-settings.c Tue Feb 22 11:59:57 2011 +0200
+++ b/src/lib-lda/lda-settings.c Tue Feb 22 13:57:20 2011 +0200
@@ -20,6 +20,7 @@
static const struct setting_define lda_setting_defines[] = {
DEF(SET_STR, postmaster_address),
DEF(SET_STR, hostname),
+ DEF(SET_STR, submission_host),
DEF(SET_STR, sendmail_path),
DEF(SET_STR, rejection_subject),
DEF(SET_STR, rejection_reason),
@@ -36,6 +37,7 @@
static const struct lda_settings lda_default_settings = {
.postmaster_address = "",
.hostname = "",
+ .submission_host = "",
.sendmail_path = "/usr/sbin/sendmail",
.rejection_subject = "Rejected: %s",
.rejection_reason =
diff -r 3053befe6a64 -r be78b9fd88e7 src/lib-lda/lda-settings.h
--- a/src/lib-lda/lda-settings.h Tue Feb 22 11:59:57 2011 +0200
+++ b/src/lib-lda/lda-settings.h Tue Feb 22 13:57:20 2011 +0200
@@ -6,12 +6,14 @@
struct lda_settings {
const char *postmaster_address;
const char *hostname;
+ const char *submission_host;
const char *sendmail_path;
const char *rejection_subject;
const char *rejection_reason;
const char *deliver_log_format;
const char *recipient_delimiter;
const char *lda_original_recipient_header;
+
bool quota_full_tempfail;
bool lda_mailbox_autocreate;
bool lda_mailbox_autosubscribe;
diff -r 3053befe6a64 -r be78b9fd88e7 src/lib-lda/smtp-client.c
--- a/src/lib-lda/smtp-client.c Tue Feb 22 11:59:57 2011 +0200
+++ b/src/lib-lda/smtp-client.c Tue Feb 22 13:57:20 2011 +0200
@@ -1,8 +1,14 @@
/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "ioloop.h"
+#include "str.h"
+#include "close-keep-errno.h"
+#include "safe-mkstemp.h"
#include "execv-const.h"
+#include "istream.h"
#include "master-service.h"
+#include "lmtp-client.h"
#include "lda-settings.h"
#include "mail-deliver.h"
#include "smtp-client.h"
@@ -11,9 +17,20 @@
#include <sys/wait.h>
#include <sysexits.h>
+#define DEFAULT_SUBMISSION_PORT 25
+
struct smtp_client {
FILE *f;
pid_t pid;
+
+ bool use_smtp;
+ bool success;
+ bool finished;
+
+ const struct lda_settings *set;
+ char *temp_path;
+ char *destination;
+ char *return_path;
};
static struct smtp_client *smtp_client_devnull(FILE **file_r)
@@ -56,9 +73,10 @@
execv_const(sendmail_path, argv);
}
-struct smtp_client *
-smtp_client_open(const struct lda_settings *set, const char *destination,
- const char *return_path, FILE **file_r)
+static struct smtp_client *
+smtp_client_open_sendmail(const struct lda_settings *set,
+ const char *destination, const char *return_path,
+ FILE **file_r)
{
struct smtp_client *client;
int fd[2];
@@ -88,11 +106,68 @@
return client;
}
-int smtp_client_close(struct smtp_client *client)
+static int create_temp_file(const char **path_r)
+{
+ string_t *path;
+ int fd;
+
+ path = t_str_new(128);
+ str_append(path, "/tmp/dovecot.");
+ str_append(path, master_service_get_name(master_service));
+ str_append_c(path, '.');
+
+ fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
+ if (fd == -1) {
+ i_error("safe_mkstemp(%s) failed: %m", str_c(path));
+ return -1;
+ }
+
+ /* we just want the fd, unlink it */
+ if (unlink(str_c(path)) < 0) {
+ /* shouldn't happen.. */
+ i_error("unlink(%s) failed: %m", str_c(path));
+ close_keep_errno(fd);
+ return -1;
+ }
+
+ *path_r = str_c(path);
+ return fd;
+}
+
+struct smtp_client *
+smtp_client_open(const struct lda_settings *set, const char *destination,
+ const char *return_path, FILE **file_r)
+{
+ struct smtp_client *client;
+ const char *path;
+ int fd;
+
+ if (*set->submission_host == '\0') {
+ return smtp_client_open_sendmail(set, destination,
+ return_path, file_r);
+ }
+
+ if ((fd = create_temp_file(&path)) == -1)
+ return smtp_client_devnull(file_r);
+
+ client = i_new(struct smtp_client, 1);
+ client->set = set;
+ client->temp_path = i_strdup(path);
+ client->destination = i_strdup(destination);
+ client->return_path = i_strdup(return_path);
+ client->f = *file_r = fdopen(fd, "w");
+ if (client->f == NULL)
+ i_fatal("fdopen() failed: %m");
+ client->use_smtp = TRUE;
+ return client;
+}
+
+static int smtp_client_close_sendmail(struct smtp_client *client)
{
int ret = EX_TEMPFAIL, status;
fclose(client->f);
+
if (client->pid == (pid_t)-1) {
/* smtp_client_open() failed already */
} else if (waitpid(client->pid, &status, 0) < 0)
@@ -113,7 +188,118 @@
i_error("Sendmail process terminated abnormally, "
"return status %d", status);
}
-
i_free(client);
return ret;
}
+
+static void smtp_client_send_finished(void *context)
+{
+ struct smtp_client *smtp_client = context;
+
+ smtp_client->finished = TRUE;
+ io_loop_stop(current_ioloop);
+}
+
+static void
+rcpt_to_callback(bool success, const char *reply, void *context)
+{
+ struct smtp_client *smtp_client = context;
+
+ if (!success) {
+ i_error("smtp(%s): RCPT TO failed: %s",
+ smtp_client->set->submission_host, reply);
+ smtp_client_send_finished(smtp_client);
+ }
+}
+
+static void
+data_callback(bool success, const char *reply, void *context)
+{
+ struct smtp_client *smtp_client = context;
+
+ if (!success) {
+ i_error("smtp(%s): DATA failed: %s",
+ smtp_client->set->submission_host, reply);
+ smtp_client_send_finished(smtp_client);
+ } else {
+ smtp_client->success = TRUE;
+ }
+}
+
+static int smtp_client_send(struct smtp_client *smtp_client)
+{
+ struct lmtp_client_settings client_set;
+ struct lmtp_client *client;
+ struct ioloop *ioloop;
+ struct istream *input;
+ const char *host, *p;
+ unsigned int port = DEFAULT_SUBMISSION_PORT;
+
+ host = smtp_client->set->submission_host;
+ p = strchr(host, ':');
+ if (p != NULL) {
+ host = t_strdup_until(host, p);
+ if (str_to_uint(p + 1, &port) < 0 ||
+ port == 0 || port > 65535) {
+ i_error("Invalid port in submission_host: %s", p+1);
+ return -1;
+ }
+ }
+
+ if (fflush(smtp_client->f) != 0) {
+ i_error("fflush(%s) failed: %m", smtp_client->temp_path);
+ return -1;
+ }
+
+ if (lseek(fileno(smtp_client->f), 0, SEEK_SET) < 0) {
+ i_error("lseek(%s) failed: %m", smtp_client->temp_path);
+ return -1;
+ }
+
+ memset(&client_set, 0, sizeof(client_set));
+ client_set.mail_from = smtp_client->return_path == NULL ? "<>" :
+ t_strconcat("<", smtp_client->return_path, ">", NULL);
+ client_set.my_hostname = smtp_client->set->hostname;
+ client_set.dns_client_socket_path = "dns-client";
+
+ ioloop = io_loop_create();
+ client = lmtp_client_init(&client_set, smtp_client_send_finished,
+ smtp_client);
+
+ if (lmtp_client_connect_tcp(client, LMTP_CLIENT_PROTOCOL_SMTP,
+ host, port) < 0) {
+ lmtp_client_deinit(&client);
+ io_loop_destroy(&ioloop);
+ return -1;
+ }
+
+ lmtp_client_add_rcpt(client, smtp_client->destination,
+ rcpt_to_callback, data_callback, smtp_client);
+
+ input = i_stream_create_fd(fileno(smtp_client->f), (size_t)-1, FALSE);
+ lmtp_client_send(client, input);
+ i_stream_unref(&input);
+
+ if (!smtp_client->finished)
+ io_loop_run(ioloop);
+ io_loop_destroy(&ioloop);
+ return smtp_client->success ? 0 : -1;
+}
+
+int smtp_client_close(struct smtp_client *client)
+{
+ int ret;
+
+ if (!client->use_smtp)
+ return smtp_client_close_sendmail(client);
+
+ /* the mail has been written to a file. now actually send it. */
+ ret = smtp_client_send(client);
+
+ fclose(client->f);
+ i_free(client->return_path);
+ i_free(client->destination);
+ i_free(client->temp_path);
+ i_free(client);
+ return ret < 0 ? EX_TEMPFAIL : 0;
+}
More information about the dovecot-cvs
mailing list