7 /* bounce service client
11 /* int bounce_append(flags, id, stats, recipient, relay, dsn)
19 /* int bounce_flush(flags, queue, id, encoding, sender,
20 /* dsn_envid, dsn_ret)
24 /* const char *encoding;
25 /* const char *sender;
26 /* const char *dsn_envid;
29 /* int bounce_flush_verp(flags, queue, id, encoding, sender,
30 /* dsn_envid, dsn_ret, verp_delims)
34 /* const char *encoding;
35 /* const char *sender;
36 /* const char *dsn_envid;
38 /* const char *verp_delims;
40 /* int bounce_one(flags, queue, id, encoding, sender, envid, ret,
41 /* stats, recipient, relay, dsn)
45 /* const char *encoding;
46 /* const char *sender;
47 /* const char *dsn_envid;
54 /* This module implements the client interface to the message
55 /* bounce service, which maintains a per-message log of status
56 /* records with recipients that were bounced, and the dsn_text why.
58 /* bounce_append() appends a dsn_text for non-delivery to the
59 /* bounce log for the named recipient, updates the address
60 /* verification service, or updates a message delivery record
61 /* on request by the sender. The flags argument determines
64 /* bounce_flush() actually bounces the specified message to
65 /* the specified sender, including the bounce log that was
66 /* built with bounce_append(). The bounce logfile is removed
67 /* upon successful completion.
69 /* bounce_flush_verp() is like bounce_flush(), but sends one
70 /* notification per recipient, with the failed recipient encoded
71 /* into the sender address.
73 /* bounce_one() bounces one recipient and immediately sends a
74 /* notification to the sender. This procedure does not append
75 /* the recipient and dsn_text to the per-message bounce log, and
76 /* should be used when a delivery agent changes the error
77 /* return address in a manner that depends on the recipient
82 /* The bitwise OR of zero or more of the following (specify
83 /* BOUNCE_FLAG_NONE to request no special processing):
85 /* .IP BOUNCE_FLAG_CLEAN
86 /* Delete the bounce log in case of an error (as in: pretend
87 /* that we never even tried to bounce this message).
88 /* .IP BOUNCE_FLAG_DELRCPT
89 /* When specified with a flush request, request that
90 /* recipients be deleted from the queue file.
92 /* Note: the bounce daemon ignores this request when the
93 /* recipient queue file offset is <= 0.
94 /* .IP DEL_REQ_FLAG_MTA_VRFY
95 /* The message is an MTA-requested address verification probe.
96 /* Update the address verification database instead of bouncing
98 /* .IP DEL_REQ_FLAG_USR_VRFY
99 /* The message is a user-requested address expansion probe.
100 /* Update the message delivery record instead of bouncing mail.
101 /* .IP DEL_REQ_FLAG_RECORD
102 /* This is a normal message with logged delivery. Update the
103 /* message delivery record and bounce the mail.
106 /* The message queue name of the original message file.
108 /* The message queue id if the original message file. The bounce log
109 /* file has the same name as the original message file.
111 /* Time stamps from different message delivery stages
112 /* and session reuse count.
114 /* Recipient information. See recipient_list(3).
116 /* Name of the host that the message could not be delivered to.
117 /* This information is used for syslogging only.
119 /* The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}.
121 /* The sender envelope address.
123 /* Optional DSN envelope ID.
125 /* Optional DSN return full/headers option.
127 /* Delivery status. See dsn(3). The specified action is ignored.
129 /* VERP delimiter characters, used when encoding the failed
130 /* sender into the envelope sender address.
132 /* In case of success, these functions log the action, and return a
133 /* zero value. Otherwise, the functions return a non-zero result,
134 /* and when BOUNCE_FLAG_CLEAN is disabled, log that message
135 /* delivery is deferred.
137 /* Should be replaced by routines with an attribute-value based
138 /* interface instead of an interface that uses a rigid argument list.
142 /* The Secure Mailer license must be distributed with this software.
145 /* IBM T.J. Watson Research
147 /* Yorktown Heights, NY 10598, USA
150 /* System library. */
152 #include <sys_defs.h>
155 /* Utility library. */
159 #include <mymalloc.h>
161 /* Global library. */
163 #include <mail_params.h>
164 #include <mail_proto.h>
165 #include <log_adhoc.h>
166 #include <dsn_util.h>
167 #include <rcpt_print.h>
168 #include <dsn_print.h>
174 /* bounce_append - append dsn_text to per-message bounce log */
176 int bounce_append(int flags
, const char *id
, MSG_STATS
*stats
,
177 RECIPIENT
*rcpt
, const char *relay
,
184 * Sanity check. If we're really confident, change this into msg_panic
185 * (remember, this information may be under control by a hostile server).
187 if (my_dsn
.status
[0] != '5' || !dsn_valid(my_dsn
.status
)) {
188 msg_warn("bounce_append: ignoring dsn code \"%s\"", my_dsn
.status
);
189 my_dsn
.status
= "5.0.0";
193 * MTA-requested address verification information is stored in the verify
196 if (flags
& DEL_REQ_FLAG_MTA_VRFY
) {
197 my_dsn
.action
= "undeliverable";
198 status
= verify_append(id
, stats
, rcpt
, relay
, &my_dsn
,
199 DEL_RCPT_STAT_BOUNCE
);
204 * User-requested address verification information is logged and mailed
205 * to the requesting user.
207 if (flags
& DEL_REQ_FLAG_USR_VRFY
) {
208 my_dsn
.action
= "undeliverable";
209 status
= trace_append(flags
, id
, stats
, rcpt
, relay
, &my_dsn
);
214 * Normal (well almost) delivery. When we're pretending that we can't
215 * bounce, don't create a defer log file when we wouldn't keep the bounce
216 * log file. That's a lot of negatives in one sentence.
218 else if (var_soft_bounce
&& (flags
& BOUNCE_FLAG_CLEAN
)) {
223 * Normal mail delivery. May also send a delivery record to the user.
225 * XXX DSN We write all recipients to the bounce logfile regardless of DSN
226 * NOTIFY options, because those options don't apply to postmaster
230 char *my_status
= mystrdup(my_dsn
.status
);
231 const char *log_status
= var_soft_bounce
? "SOFTBOUNCE" : "bounced";
234 * Supply default action.
236 my_dsn
.status
= my_status
;
237 if (var_soft_bounce
) {
239 my_dsn
.action
= "delayed";
241 my_dsn
.action
= "failed";
244 if (mail_command_client(MAIL_CLASS_PRIVATE
, var_soft_bounce
?
245 var_defer_service
: var_bounce_service
,
246 ATTR_TYPE_INT
, MAIL_ATTR_NREQ
, BOUNCE_CMD_APPEND
,
247 ATTR_TYPE_INT
, MAIL_ATTR_FLAGS
, flags
,
248 ATTR_TYPE_STR
, MAIL_ATTR_QUEUEID
, id
,
249 ATTR_TYPE_FUNC
, rcpt_print
, (void *) rcpt
,
250 ATTR_TYPE_FUNC
, dsn_print
, (void *) &my_dsn
,
252 && ((flags
& DEL_REQ_FLAG_RECORD
) == 0
253 || trace_append(flags
, id
, stats
, rcpt
, relay
,
255 log_adhoc(id
, stats
, rcpt
, relay
, &my_dsn
, log_status
);
256 status
= (var_soft_bounce
? -1 : 0);
257 } else if ((flags
& BOUNCE_FLAG_CLEAN
) == 0) {
258 VSTRING
*junk
= vstring_alloc(100);
260 my_dsn
.status
= "4.3.0";
261 vstring_sprintf(junk
, "%s or %s service failure",
262 var_bounce_service
, var_trace_service
);
263 my_dsn
.reason
= vstring_str(junk
);
264 status
= defer_append(flags
, id
, stats
, rcpt
, relay
, &my_dsn
);
274 /* bounce_flush - flush the bounce log and deliver to the sender */
276 int bounce_flush(int flags
, const char *queue
, const char *id
,
277 const char *encoding
, const char *sender
,
278 const char *dsn_envid
, int dsn_ret
)
282 * When we're pretending that we can't bounce, don't send a bounce
287 if (mail_command_client(MAIL_CLASS_PRIVATE
, var_bounce_service
,
288 ATTR_TYPE_INT
, MAIL_ATTR_NREQ
, BOUNCE_CMD_FLUSH
,
289 ATTR_TYPE_INT
, MAIL_ATTR_FLAGS
, flags
,
290 ATTR_TYPE_STR
, MAIL_ATTR_QUEUE
, queue
,
291 ATTR_TYPE_STR
, MAIL_ATTR_QUEUEID
, id
,
292 ATTR_TYPE_STR
, MAIL_ATTR_ENCODING
, encoding
,
293 ATTR_TYPE_STR
, MAIL_ATTR_SENDER
, sender
,
294 ATTR_TYPE_STR
, MAIL_ATTR_DSN_ENVID
, dsn_envid
,
295 ATTR_TYPE_INT
, MAIL_ATTR_DSN_RET
, dsn_ret
,
296 ATTR_TYPE_END
) == 0) {
298 } else if ((flags
& BOUNCE_FLAG_CLEAN
) == 0) {
299 msg_info("%s: status=deferred (bounce failed)", id
);
306 /* bounce_flush_verp - verpified notification */
308 int bounce_flush_verp(int flags
, const char *queue
, const char *id
,
309 const char *encoding
, const char *sender
,
310 const char *dsn_envid
, int dsn_ret
,
311 const char *verp_delims
)
315 * When we're pretending that we can't bounce, don't send a bounce
320 if (mail_command_client(MAIL_CLASS_PRIVATE
, var_bounce_service
,
321 ATTR_TYPE_INT
, MAIL_ATTR_NREQ
, BOUNCE_CMD_VERP
,
322 ATTR_TYPE_INT
, MAIL_ATTR_FLAGS
, flags
,
323 ATTR_TYPE_STR
, MAIL_ATTR_QUEUE
, queue
,
324 ATTR_TYPE_STR
, MAIL_ATTR_QUEUEID
, id
,
325 ATTR_TYPE_STR
, MAIL_ATTR_ENCODING
, encoding
,
326 ATTR_TYPE_STR
, MAIL_ATTR_SENDER
, sender
,
327 ATTR_TYPE_STR
, MAIL_ATTR_DSN_ENVID
, dsn_envid
,
328 ATTR_TYPE_INT
, MAIL_ATTR_DSN_RET
, dsn_ret
,
329 ATTR_TYPE_STR
, MAIL_ATTR_VERPDL
, verp_delims
,
330 ATTR_TYPE_END
) == 0) {
332 } else if ((flags
& BOUNCE_FLAG_CLEAN
) == 0) {
333 msg_info("%s: status=deferred (bounce failed)", id
);
340 /* bounce_one - send notice for one recipient */
342 int bounce_one(int flags
, const char *queue
, const char *id
,
343 const char *encoding
, const char *sender
,
344 const char *dsn_envid
, int dsn_ret
,
345 MSG_STATS
*stats
, RECIPIENT
*rcpt
,
346 const char *relay
, DSN
*dsn
)
354 if (my_dsn
.status
[0] != '5' || !dsn_valid(my_dsn
.status
)) {
355 msg_warn("bounce_one: ignoring dsn code \"%s\"", my_dsn
.status
);
356 my_dsn
.status
= "5.0.0";
360 * MTA-requested address verification information is stored in the verify
363 if (flags
& DEL_REQ_FLAG_MTA_VRFY
) {
364 my_dsn
.action
= "undeliverable";
365 status
= verify_append(id
, stats
, rcpt
, relay
, &my_dsn
,
366 DEL_RCPT_STAT_BOUNCE
);
371 * User-requested address verification information is logged and mailed
372 * to the requesting user.
374 if (flags
& DEL_REQ_FLAG_USR_VRFY
) {
375 my_dsn
.action
= "undeliverable";
376 status
= trace_append(flags
, id
, stats
, rcpt
, relay
, &my_dsn
);
381 * When we're not bouncing, then use the standard multi-recipient logfile
384 else if (var_soft_bounce
) {
385 return (bounce_append(flags
, id
, stats
, rcpt
, relay
, &my_dsn
));
389 * Normal mail delivery. May also send a delivery record to the user.
391 * XXX DSN We send all recipients regardless of DSN NOTIFY options, because
392 * those options don't apply to postmaster notifications.
397 * Supply default action.
399 my_dsn
.action
= "failed";
401 if (mail_command_client(MAIL_CLASS_PRIVATE
, var_bounce_service
,
402 ATTR_TYPE_INT
, MAIL_ATTR_NREQ
, BOUNCE_CMD_ONE
,
403 ATTR_TYPE_INT
, MAIL_ATTR_FLAGS
, flags
,
404 ATTR_TYPE_STR
, MAIL_ATTR_QUEUE
, queue
,
405 ATTR_TYPE_STR
, MAIL_ATTR_QUEUEID
, id
,
406 ATTR_TYPE_STR
, MAIL_ATTR_ENCODING
, encoding
,
407 ATTR_TYPE_STR
, MAIL_ATTR_SENDER
, sender
,
408 ATTR_TYPE_STR
, MAIL_ATTR_DSN_ENVID
, dsn_envid
,
409 ATTR_TYPE_INT
, MAIL_ATTR_DSN_RET
, dsn_ret
,
410 ATTR_TYPE_FUNC
, rcpt_print
, (void *) rcpt
,
411 ATTR_TYPE_FUNC
, dsn_print
, (void *) &my_dsn
,
413 && ((flags
& DEL_REQ_FLAG_RECORD
) == 0
414 || trace_append(flags
, id
, stats
, rcpt
, relay
,
416 log_adhoc(id
, stats
, rcpt
, relay
, &my_dsn
, "bounced");
418 } else if ((flags
& BOUNCE_FLAG_CLEAN
) == 0) {
419 VSTRING
*junk
= vstring_alloc(100);
421 my_dsn
.status
= "4.3.0";
422 vstring_sprintf(junk
, "%s or %s service failure",
423 var_bounce_service
, var_trace_service
);
424 my_dsn
.reason
= vstring_str(junk
);
425 status
= defer_append(flags
, id
, stats
, rcpt
, relay
, &my_dsn
);