1
/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
8
#include "str-sanitize.h"
9
#include "var-expand.h"
10
#include "message-date.h"
11
#include "message-size.h"
12
#include "duplicate.h"
13
#include "istream-header-filter.h"
14
#include "smtp-client.h"
16
#include "mail-send.h"
21
int global_outgoing_count = 0;
23
static const struct var_expand_table *
24
get_var_expand_table(struct mail *mail, const char *reason,
25
const char *recipient)
27
static struct var_expand_table static_tab[] = {
28
{ 'n', NULL, "crlf" },
29
{ 'r', NULL, "reason" },
30
{ 's', NULL, "subject" },
34
struct var_expand_table *tab;
37
tab = t_malloc(sizeof(static_tab));
38
memcpy(tab, static_tab, sizeof(static_tab));
40
tab[0].value = "\r\n";
41
tab[1].value = reason;
42
if (mail_get_first_header(mail, "Subject", &subject) <= 0)
44
tab[2].value = str_sanitize(subject, 80);
45
tab[3].value = recipient;
50
int mail_send_rejection(struct mail *mail, const char *recipient,
53
struct istream *input;
54
struct smtp_client *smtp_client;
56
struct message_size hdr_size;
57
const char *return_addr, *hdr;
58
const unsigned char *data;
59
const char *value, *msgid, *orig_msgid, *boundary;
64
if (mail_get_first_header(mail, "Auto-Submitted", &value) > 0 &&
65
strcasecmp(value, "no") != 0) {
66
i_info("msgid=%s: Auto-submitted message discarded: %s",
67
orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80),
68
str_sanitize(reason, 512));
72
if (mail_get_first_header(mail, "Message-ID", &orig_msgid) < 0)
74
return_addr = deliver_get_return_address(mail);
75
if (return_addr == NULL) {
76
i_info("msgid=%s: Return-Path missing, rejection reason: %s",
77
orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80),
78
str_sanitize(reason, 512));
82
if (getenv("DEBUG") != NULL) {
83
i_info("Sending a rejection to %s: %s", recipient,
84
str_sanitize(reason, 512));
87
smtp_client = smtp_client_open(return_addr, NULL, &f);
89
msgid = deliver_get_new_message_id();
90
boundary = t_strdup_printf("%s/%s", my_pid, deliver_set->hostname);
92
fprintf(f, "Message-ID: %s\r\n", msgid);
93
fprintf(f, "Date: %s\r\n", message_date_create(ioloop_time));
94
fprintf(f, "From: Mail Delivery Subsystem <%s>\r\n",
95
deliver_set->postmaster_address);
96
fprintf(f, "To: <%s>\r\n", return_addr);
97
fprintf(f, "MIME-Version: 1.0\r\n");
98
fprintf(f, "Content-Type: "
99
"multipart/report; report-type=disposition-notification;\r\n"
100
"\tboundary=\"%s\"\r\n", boundary);
102
str = t_str_new(256);
103
var_expand(str, deliver_set->rejection_subject,
104
get_var_expand_table(mail, reason, recipient));
105
fprintf(f, "Subject: %s\r\n", str_c(str));
107
fprintf(f, "Auto-Submitted: auto-replied (rejected)\r\n");
108
fprintf(f, "Precedence: bulk\r\n");
109
fprintf(f, "\r\nThis is a MIME-encapsulated message\r\n\r\n");
111
/* human readable status report */
112
fprintf(f, "--%s\r\n", boundary);
113
fprintf(f, "Content-Type: text/plain; charset=utf-8\r\n");
114
fprintf(f, "Content-Disposition: inline\r\n");
115
fprintf(f, "Content-Transfer-Encoding: 8bit\r\n\r\n");
117
str_truncate(str, 0);
118
var_expand(str, deliver_set->rejection_reason,
119
get_var_expand_table(mail, reason, recipient));
120
fprintf(f, "%s\r\n", str_c(str));
122
/* MDN status report */
123
fprintf(f, "--%s\r\n"
124
"Content-Type: message/disposition-notification\r\n\r\n",
126
fprintf(f, "Reporting-UA: %s; Dovecot Mail Delivery Agent\r\n",
127
deliver_set->hostname);
128
if (mail_get_first_header(mail, "Original-Recipient", &hdr) > 0)
129
fprintf(f, "Original-Recipient: rfc822; %s\r\n", hdr);
130
fprintf(f, "Final-Recipient: rfc822; %s\r\n", recipient);
132
if (orig_msgid != NULL)
133
fprintf(f, "Original-Message-ID: %s\r\n", orig_msgid);
134
fprintf(f, "Disposition: "
135
"automatic-action/MDN-sent-automatically; deleted\r\n");
138
/* original message's headers */
139
fprintf(f, "--%s\r\nContent-Type: message/rfc822\r\n\r\n", boundary);
141
if (mail_get_stream(mail, &hdr_size, NULL, &input) == 0) {
142
/* Note: If you add more headers, they need to be sorted.
143
We'll drop Content-Type because we're not including the message
144
body, and having a multipart Content-Type may confuse some
145
MIME parsers when they don't see the message boundaries. */
146
static const char *const exclude_headers[] = {
150
input = i_stream_create_header_filter(input,
151
HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR |
152
HEADER_FILTER_HIDE_BODY, exclude_headers,
153
N_ELEMENTS(exclude_headers),
154
null_header_filter_callback, NULL);
156
while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
157
if (fwrite(data, size, 1, f) == 0)
159
i_stream_skip(input, size);
161
i_stream_unref(&input);
166
fprintf(f, "\r\n\r\n--%s--\r\n", boundary);
167
return smtp_client_close(smtp_client);
170
int mail_send_forward(struct mail *mail, const char *forwardto)
172
static const char *hide_headers[] = {
175
struct istream *input;
176
struct smtp_client *smtp_client;
178
const unsigned char *data;
179
const char *return_path;
183
if (mail_get_stream(mail, NULL, NULL, &input) < 0)
186
return_path = deliver_get_return_address(mail);
187
if (getenv("DEBUG") != NULL) {
188
i_info("Sending a forward to <%s> with return path <%s>",
189
forwardto, return_path);
192
smtp_client = smtp_client_open(forwardto, return_path, &f);
194
input = i_stream_create_header_filter(input, HEADER_FILTER_EXCLUDE |
195
HEADER_FILTER_NO_CR, hide_headers,
196
N_ELEMENTS(hide_headers),
197
null_header_filter_callback, NULL);
199
while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
200
if (fwrite(data, size, 1, f) == 0)
202
i_stream_skip(input, size);
204
i_stream_unref(&input);
206
return smtp_client_close(smtp_client);