📄 dsnbounce.java
字号:
// per recipient fields // ////////////////////////// Iterator recipients = originalMail.getRecipients().iterator(); while (recipients.hasNext()) { MailAddress rec = (MailAddress)recipients.next(); String addressType = "rfc822"; //required: blank line out.println(); //optional: original recipient (see RFC3461) //out.println("Original-Recipient: "+addressType+"; "+ ??? ); //required: final recipient out.println("Final-Recipient: "+addressType+"; "+rec.toString()); //required: action // alowed values: failed, delayed, delivered, relayed, expanded // TODO: until now, we do error-bounces only out.println("Action: failed"); //required: status // get Exception for getting status information // TODO: it would be nice if the SMTP-handler would set a status attribute we can use here MessagingException ex = (MessagingException) originalMail.getAttribute("delivery-error"); out.println("Status: "+getStatus(ex)); //optional: remote MTA //to which MTA were we talking while the Error occured? //optional: diagnostic-code String diagnosticType = null; // this typically is the return value received during smtp // (or other transport) communication // and should be stored as attribute by the smtp handler // but until now we only have error-messages. String diagnosticCode = getErrorMsg(ex); // Sometimes this is the smtp diagnostic code, // but James often gives us other messages Perl5Matcher diagMatcher = new Perl5Matcher(); boolean smtpDiagCodeAvailable = diagMatcher.matches(diagnosticCode, diagPattern); if (smtpDiagCodeAvailable){ diagnosticType = "smtp"; } else { diagnosticType = "X-James"; } out.println("Diagnostic-Code: "+diagnosticType+"; "+diagnosticCode); //optional: last attempt out.println("Last-Attempt-Date: "+ rfc822DateFormat.format(originalMail.getLastUpdated())); //optional: retry until //only for 'delayed' reports .. but we don't report this (at least until now) //optional: extension fields } // Changed this from rfc822 handling to text/plain // It should be handled correctly as delivery-status but it // is better text/plain than rfc822 (rfc822 add message headers not // allowed in the delivery-status. // text/plain does not support rfc822 header encoding that we // should support here. dsn.setContent(sout.toString(), "text/plain"); dsn.setHeader("Content-Type","message/delivery-status"); dsn.setDescription("Delivery Status Notification"); dsn.setFileName("status.dat"); return dsn; } /** * Create a MimeBodyPart with the original Mail as Attachment * * @param originalMail * @return MimeBodyPart * @throws MessagingException */ protected MimeBodyPart createAttachedOriginal(Mail originalMail, int attachmentType) throws MessagingException { MimeBodyPart part = new MimeBodyPart(); MimeMessage originalMessage = originalMail.getMessage(); if (attachmentType == HEADS) { part.setContent(getMessageHeaders(originalMessage), "text/plain"); part.setHeader("Content-Type","text/rfc822-headers"); } else { part.setContent(originalMessage, "message/rfc822"); } if ((originalMessage.getSubject() != null) && (originalMessage.getSubject().trim().length() > 0)) { part.setFileName(originalMessage.getSubject().trim()); } else { part.setFileName("No Subject"); } part.setDisposition("Attachment"); return part; } /** * Guessing status code by the exception provided. * This method should use the status attribute when the * SMTP-handler somewhen provides it * * @param MessagingException * @return status code */ protected String getStatus(MessagingException me) { if (me.getNextException() == null) { String mess = me.getMessage(); Perl5Matcher m = new Perl5Matcher(); StringBuffer sb = new StringBuffer(); if (m.matches(mess, statusPattern)) { MatchResult res = m.getMatch(); sb.append(res.group(1)); return sb.toString(); } // bad destination system adress if (mess.startsWith("There are no DNS entries for the hostname")) return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.ADDRESS_SYSTEM); // no answer from host (4.4.1) or // system not accepting network messages (4.3.2), lets guess ... if (mess.equals("No mail server(s) available at this time.")) return DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.NETWORK_NO_ANSWER); // other/unknown error return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.UNDEFINED_STATUS); } else { Exception ex1 = me.getNextException(); Perl5Matcher m = new Perl5Matcher (); StringBuffer sb = new StringBuffer(); if (m.matches(ex1.getMessage(), statusPattern)) { MatchResult res = m.getMatch(); sb.append(res.group(1)); return sb.toString(); } else if (ex1 instanceof SendFailedException) { // other/undefined protocol status int smtpCode = 0; try { smtpCode = Integer.parseInt(ex1.getMessage().substring(0,3)); } catch(NumberFormatException e) { } switch (smtpCode) { // Req mail action not taken: mailbox unavailable case 450: return DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.MAILBOX_OTHER); // Req action aborted: local error in processing case 451: return DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.SYSTEM_OTHER); // Req action not taken: insufficient sys storage case 452: return DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.SYSTEM_FULL); // Syntax error, command unrecognized case 500: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_SYNTAX); // Syntax error in parameters or arguments case 501: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_ARG); // Command not implemented case 502: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_CMD); // Bad sequence of commands case 503: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_CMD); // Command parameter not implemented case 504: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_ARG); // Req mail action not taken: mailbox unavailable case 550: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.MAILBOX_OTHER); // User not local; please try <...> // 5.7.1 Select another host to act as your forwarder case 551: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.SECURITY_AUTH); // Req mail action aborted: exceeded storage alloc case 552: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.MAILBOX_FULL); // Req action not taken: mailbox name not allowed case 553: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.ADDRESS_SYNTAX); // Transaction failed case 554: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.UNDEFINED_STATUS); // Not authorized. This is not an SMTP code, but many server use it. case 571: return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.SECURITY_AUTH); default: // if we get an smtp returncode starting with 4 // it is an persistent transient error, else permanent if (ex1.getMessage().startsWith("4")) { return DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.DELIVERY_OTHER); } else return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_OTHER); } } else if (ex1 instanceof UnknownHostException) { // bad destination system address return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.ADDRESS_SYSTEM); } else if (ex1 instanceof ConnectException) { // bad connection return DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.NETWORK_CONNECTION); } else if (ex1 instanceof SocketException) { // bad connection return DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.NETWORK_CONNECTION); } else { // other/undefined/unknown error return DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.UNDEFINED_STATUS); } } } /** * Utility method for getting the error message from the (nested) exception. * @param MessagingException * @return error message */ protected String getErrorMsg(MessagingException me) { if (me.getNextException() == null) { return me.getMessage().trim(); } else { Exception ex1 = me.getNextException(); return ex1.getMessage().trim(); } } /** * Utility method for obtaining a string representation of an array of Objects. */ private String arrayToString(Object[] array) { if (array == null) { return "null"; } StringBuffer sb = new StringBuffer(1024); sb.append("["); for (int i = 0; i < array.length; i++) { if (i > 0) { sb.append(","); } sb.append(array[i]); } sb.append("]"); return sb.toString(); } /** * Create a unique new primary key name. * * @param mail the mail to use as the basis for the new mail name * @return a new name */ protected String newName(Mail mail) throws MessagingException { String oldName = mail.getName(); // Checking if the original mail name is too long, perhaps because of a // loop caused by a configuration error. // it could cause a "null pointer exception" in AvalonMailRepository much // harder to understand. if (oldName.length() > 76) { int count = 0; int index = 0; while ((index = oldName.indexOf('!', index + 1)) >= 0) { count++; } // It looks like a configuration loop. It's better to stop. if (count > 7) { throw new MessagingException("Unable to create a new message name: too long." + " Possible loop in config.xml."); } else { oldName = oldName.substring(0, 76); } } StringBuffer nameBuffer = new StringBuffer(64) .append(oldName) .append("-!") .append(random.nextInt(1048576)); return nameBuffer.toString(); } public String getMailetInfo() { return "DSNBounce Mailet"; } /* ******************************************************************** */ /* ****************** Begin of getX and setX methods ****************** */ /* ******************************************************************** */ /** Gets the expected init parameters. */ protected String[] getAllowedInitParameters() { String[] allowedArray = { "debug", "passThrough", "messageString", "attachment", "sender", "prefix" }; return allowedArray; } /** * @return the <CODE>attachment</CODE> init parameter, or <CODE>MESSAGE</CODE> if missing */ protected int getAttachmentType() throws MessagingException { return getTypeCode(getInitParameter("attachment","message")); } /** * @return <CODE>SpecialAddress.REVERSE_PATH</CODE> */ protected Collection getRecipients() { Collection newRecipients = new HashSet(); newRecipients.add(SpecialAddress.REVERSE_PATH); return newRecipients; } /** * @return <CODE>SpecialAddress.REVERSE_PATH</CODE> */ protected InternetAddress[] getTo() { InternetAddress[] apparentlyTo = new InternetAddress[1]; apparentlyTo[0] = SpecialAddress.REVERSE_PATH.toInternetAddress(); return apparentlyTo; } /** * @return <CODE>SpecialAddress.NULL</CODE> (the meaning of bounce) */ protected MailAddress getReversePath(Mail originalMail) { return SpecialAddress.NULL; } /* ******************************************************************** */ /* ******************* End of getX and setX methods ******************* */ /* ******************************************************************** */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -