5 /* bounce_notify_verp 3
7 /* send non-delivery report to sender, server side
9 /* #include "bounce_service.h"
11 /* int bounce_notify_verp(flags, service, queue_name, queue_id, sender,
12 /* dsn_envid, dsn_ret, verp_delims,
21 /* BOUNCE_TEMPLATES *templates;
23 /* This module implements the server side of the bounce_notify()
24 /* (send bounce message) request. The logfile
25 /* is removed after and a warning is posted.
26 /* The bounce recipient address is encoded in VERP format.
27 /* This routine must be used for single bounces only.
29 /* When a message bounces, a full copy is sent to the originator,
30 /* and an optional copy of the diagnostics with message headers is
31 /* sent to the postmaster. The result is non-zero when the operation
32 /* should be tried again.
34 /* When a bounce is sent, the sender address is the empty
37 /* Fatal error: error opening existing file.
39 /* bounce(3) basic bounce service client interface
43 /* The Secure Mailer license must be distributed with this software.
46 /* IBM T.J. Watson Research
48 /* Yorktown Heights, NY 10598, USA
59 #ifdef STRCASECMP_IN_STRINGS_H
63 /* Utility library. */
67 #include <name_mask.h>
71 #include <mail_params.h>
72 #include <mail_queue.h>
73 #include <post_mail.h>
74 #include <mail_addr.h>
75 #include <mail_error.h>
76 #include <verp_sender.h>
80 /* Application-specific. */
82 #include "bounce_service.h"
84 #define STR vstring_str
86 /* bounce_notify_verp - send a bounce, VERP style */
88 int bounce_notify_verp(int flags
, char *service
, char *queue_name
,
89 char *queue_id
, char *encoding
,
90 char *recipient
, char *dsn_envid
,
91 int dsn_ret
, char *verp_delims
,
94 const char *myname
= "bounce_notify_verp";
95 BOUNCE_INFO
*bounce_info
;
96 int bounce_status
= 0;
97 int postmaster_status
;
99 int notify_mask
= name_mask(VAR_NOTIFY_CLASSES
, mail_error_masks
,
106 * Sanity checks. We must be called only for undeliverable non-bounce
110 msg_panic("%s: attempt to bounce a single bounce", myname
);
111 if (strcasecmp(recipient
, mail_addr_double_bounce()) == 0)
112 msg_panic("%s: attempt to bounce a double bounce", myname
);
115 * Initialize. Open queue file, bounce log, etc.
117 bounce_info
= bounce_mail_init(service
, queue_name
, queue_id
,
118 encoding
, dsn_envid
, ts
->failure
);
121 * If we have no recipient list then we can't send VERP replies. Send
122 * *something* anyway so that the mail is not lost in a black hole.
124 if (bounce_info
->log_handle
== 0) {
125 DSN_BUF
*dsn_buf
= dsb_create();
126 RCPT_BUF
*rcpt_buf
= rcpb_create();
128 dsb_simple(dsn_buf
, "5.0.0", "(error report unavailable)");
129 (void) DSN_FROM_DSN_BUF(dsn_buf
);
130 vstring_strcpy(rcpt_buf
->address
, "(recipient address unavailable)");
131 (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf
);
132 bounce_status
= bounce_one_service(flags
, queue_name
, queue_id
,
133 encoding
, recipient
, dsn_envid
,
134 dsn_ret
, rcpt_buf
, dsn_buf
, ts
);
137 bounce_mail_free(bounce_info
);
138 return (bounce_status
);
140 #define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
141 #define NULL_TRACE_FLAGS 0
144 * A non-bounce message was returned. Send a single bounce, one per
147 verp_buf
= vstring_alloc(100);
148 new_id
= vstring_alloc(10);
149 while (bounce_log_read(bounce_info
->log_handle
, bounce_info
->rcpt_buf
,
150 bounce_info
->dsn_buf
) != 0) {
151 RECIPIENT
*rcpt
= &bounce_info
->rcpt_buf
->rcpt
;
154 * Notify the originator, subject to DSN NOTIFY restrictions.
156 * Fix 20090114: Use the Postfix original recipient, because that is
157 * what the VERP consumer expects.
159 if (rcpt
->dsn_notify
!= 0 /* compat */
160 && (rcpt
->dsn_notify
& DSN_NOTIFY_FAILURE
) == 0) {
163 verp_sender(verp_buf
, verp_delims
, recipient
, rcpt
);
164 if ((bounce
= post_mail_fopen_nowait(NULL_SENDER
, STR(verp_buf
),
165 INT_FILT_MASK_BOUNCE
,
170 * Send the bounce message header, some boilerplate text that
171 * pretends that we are a polite mail system, the text with
172 * reason for the bounce, and a copy of the original message.
174 if (bounce_header(bounce
, bounce_info
, STR(verp_buf
),
175 NO_POSTMASTER_COPY
) == 0
176 && bounce_boilerplate(bounce
, bounce_info
) == 0
177 && bounce_recipient_log(bounce
, bounce_info
) == 0
178 && bounce_header_dsn(bounce
, bounce_info
) == 0
179 && bounce_recipient_dsn(bounce
, bounce_info
) == 0)
180 bounce_original(bounce
, bounce_info
, dsn_ret
?
181 dsn_ret
: DSN_RET_FULL
);
182 bounce_status
= post_mail_fclose(bounce
);
183 if (bounce_status
== 0)
184 msg_info("%s: sender non-delivery notification: %s",
185 queue_id
, STR(new_id
));
190 * Stop at the first sign of trouble, instead of making the
193 if (bounce_status
!= 0)
197 * Optionally, mark this recipient as done.
199 if (flags
& BOUNCE_FLAG_DELRCPT
)
200 bounce_delrcpt_one(bounce_info
);
204 * Optionally, send a postmaster notice, subject to notify_classes
207 * This postmaster notice is not critical, so if it fails don't
208 * retransmit the bounce that we just generated, just log a warning.
210 #define SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE (notify_mask & MAIL_ERROR_BOUNCE)
212 if (SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE
) {
215 * Send the text with reason for the bounce, and the headers of
216 * the original message. Don't bother sending the boiler-plate
217 * text. This postmaster notice is not critical, so if it fails
218 * don't retransmit the bounce that we just generated, just log a
221 postmaster
= var_bounce_rcpt
;
222 if ((bounce
= post_mail_fopen_nowait(mail_addr_double_bounce(),
224 INT_FILT_MASK_BOUNCE
,
227 if (bounce_header(bounce
, bounce_info
, postmaster
,
228 POSTMASTER_COPY
) == 0
229 && bounce_recipient_log(bounce
, bounce_info
) == 0
230 && bounce_header_dsn(bounce
, bounce_info
) == 0
231 && bounce_recipient_dsn(bounce
, bounce_info
) == 0)
232 bounce_original(bounce
, bounce_info
, DSN_RET_HDRS
);
233 postmaster_status
= post_mail_fclose(bounce
);
234 if (postmaster_status
== 0)
235 msg_info("%s: postmaster non-delivery notification: %s",
236 queue_id
, STR(new_id
));
238 postmaster_status
= 1;
240 if (postmaster_status
)
241 msg_warn("%s: postmaster notice failed while bouncing to %s",
242 queue_id
, recipient
);
247 * Examine the completion status. Delete the bounce log file only when
248 * the bounce was posted successfully, and only if we are bouncing for
249 * real, not just warning.
251 if (bounce_status
== 0 && mail_queue_remove(service
, queue_id
)
253 msg_fatal("remove %s %s: %m", service
, queue_id
);
258 bounce_mail_free(bounce_info
);
259 vstring_free(verp_buf
);
260 vstring_free(new_id
);
262 return (bounce_status
);