Released v1.1.14.
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[] = {
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 *msgid, *orig_msgid, *boundary;
64 if (mail_get_first_header(mail, "Message-ID", &orig_msgid) < 0)
66 return_addr = deliver_get_return_address(mail);
67 if (return_addr == NULL) {
68 i_info("msgid=%s: Return-Path missing, rejection reason: %s",
69 orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80),
70 str_sanitize(reason, 512));
74 if (getenv("DEBUG") != NULL) {
75 i_info("Sending a rejection to %s: %s", recipient,
76 str_sanitize(reason, 512));
79 smtp_client = smtp_client_open(return_addr, NULL, &f);
81 msgid = deliver_get_new_message_id();
82 boundary = t_strdup_printf("%s/%s", my_pid, deliver_set->hostname);
84 fprintf(f, "Message-ID: %s\r\n", msgid);
85 fprintf(f, "Date: %s\r\n", message_date_create(ioloop_time));
86 fprintf(f, "From: Mail Delivery Subsystem <%s>\r\n",
87 deliver_set->postmaster_address);
88 fprintf(f, "To: <%s>\r\n", return_addr);
89 fprintf(f, "MIME-Version: 1.0\r\n");
90 fprintf(f, "Content-Type: "
91 "multipart/report; report-type=disposition-notification;\r\n"
92 "\tboundary=\"%s\"\r\n", boundary);
95 var_expand(str, deliver_set->rejection_subject,
96 get_var_expand_table(mail, reason, recipient));
97 fprintf(f, "Subject: %s\r\n", str_c(str));
99 fprintf(f, "Auto-Submitted: auto-replied (rejected)\r\n");
100 fprintf(f, "Precedence: bulk\r\n");
101 fprintf(f, "\r\nThis is a MIME-encapsulated message\r\n\r\n");
103 /* human readable status report */
104 fprintf(f, "--%s\r\n", boundary);
105 fprintf(f, "Content-Type: text/plain; charset=utf-8\r\n");
106 fprintf(f, "Content-Disposition: inline\r\n");
107 fprintf(f, "Content-Transfer-Encoding: 8bit\r\n\r\n");
109 str_truncate(str, 0);
110 var_expand(str, deliver_set->rejection_reason,
111 get_var_expand_table(mail, reason, recipient));
112 fprintf(f, "%s\r\n", str_c(str));
114 /* MDN status report */
115 fprintf(f, "--%s\r\n"
116 "Content-Type: message/disposition-notification\r\n\r\n",
118 fprintf(f, "Reporting-UA: %s; Dovecot Mail Delivery Agent\r\n",
119 deliver_set->hostname);
120 if (mail_get_first_header(mail, "Original-Recipient", &hdr) > 0)
121 fprintf(f, "Original-Recipient: rfc822; %s\r\n", hdr);
122 fprintf(f, "Final-Recipient: rfc822; %s\r\n", recipient);
124 if (orig_msgid != NULL)
125 fprintf(f, "Original-Message-ID: %s\r\n", orig_msgid);
126 fprintf(f, "Disposition: "
127 "automatic-action/MDN-sent-automatically; deleted\r\n");
130 /* original message's headers */
131 fprintf(f, "--%s\r\nContent-Type: message/rfc822\r\n\r\n", boundary);
133 if (mail_get_stream(mail, &hdr_size, NULL, &input) == 0) {
134 /* Note: If you add more headers, they need to be sorted.
135 We'll drop Content-Type because we're not including the message
136 body, and having a multipart Content-Type may confuse some
137 MIME parsers when they don't see the message boundaries. */
138 static const char *const exclude_headers[] = {
142 input = i_stream_create_header_filter(input,
143 HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR |
144 HEADER_FILTER_HIDE_BODY, exclude_headers,
145 N_ELEMENTS(exclude_headers),
146 null_header_filter_callback, NULL);
148 while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
149 if (fwrite(data, size, 1, f) == 0)
151 i_stream_skip(input, size);
153 i_stream_unref(&input);
158 fprintf(f, "\r\n\r\n--%s--\r\n", boundary);
159 return smtp_client_close(smtp_client);
162 int mail_send_forward(struct mail *mail, const char *forwardto)
164 static const char *hide_headers[] = {
167 struct istream *input;
168 struct smtp_client *smtp_client;
170 const unsigned char *data;
171 const char *return_path;
175 if (mail_get_stream(mail, NULL, NULL, &input) < 0)
178 if (mail_get_first_header(mail, "Return-Path", &return_path) <= 0)
181 if (getenv("DEBUG") != NULL) {
182 i_info("Sending a forward to <%s> with return path <%s>",
183 forwardto, return_path);
186 smtp_client = smtp_client_open(forwardto, return_path, &f);
188 input = i_stream_create_header_filter(input, HEADER_FILTER_EXCLUDE |
189 HEADER_FILTER_NO_CR, hide_headers,
190 N_ELEMENTS(hide_headers),
191 null_header_filter_callback, NULL);
193 while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
194 if (fwrite(data, size, 1, f) == 0)
196 i_stream_skip(input, size);
198 i_stream_unref(&input);
200 return smtp_client_close(smtp_client);