Spring JavaMailSenderImpl выдает исключение, но все равно отправляет электронное письмо

Используя Spring 3.0, я написал интерфейс, чтобы скрыть от приложения, какой механизм шаблонов я использовал для отправки почты. Интерфейс

public interface MailSender {
    public void send(String[] to, String from, String subject, String template,
        Map<Object, Object> model, boolean isHtml,
        Map<String, Resource> attachments,
        Map<String, Resource> inline) throws MailException;
}

Тогда реализация Velocity

public class MailSenderVelocity implements MailSender {
    private JavaMailSender sender;
    private VelocityEngine engine;

    @Override
    public void send(final String[] to, final String from,
        final String subject, final String template,
        final Map<Object, Object> model, final boolean isHtml,
        final Map<String, Resource> attachments,
        final Map<String, Resource> inline)
            throws com.engrid.mail.MailException {
        try {
            // prepare the message to send
            MimeMessagePreparator preparator = new MimeMessagePreparator() {
                @Override
                public void prepare(MimeMessage mimeMessage) throws Exception {
                    // determine if the message needs to be multipart or not
                    boolean multipart = (attachments != null && !attachments.isEmpty()) || (inline != null && !inline.isEmpty());

                    // create the message
                    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, multipart);

                    // populate header fields
                    helper.setTo(to);
                    helper.setFrom(from);
                    helper.setSubject(subject);

                    // fetch template and merge model
                    String text = VelocityEngineUtils.mergeTemplateIntoString(engine, template, model);
                    helper.setText(text, isHtml);

                    // add inline attachments
                    if (inline != null) {
                        for (Entry<String, Resource> entry : inline.entrySet()) {
                            helper.addInline(entry.getKey(), entry.getValue());
                        }
                    }

                    // add other attachments
                    if (attachments != null) {
                        for (Entry<String, Resource> entry : attachments.entrySet()) {
                            helper.addAttachment(entry.getKey(), entry.getValue());
                        }
                    }
                }
            };

            // send the email
            this.sender.send(preparator);
        } catch(MailException e) {
            // error preparing or sending the message
            e.printStackTrace();
            throw new com.engrid.mail.MailException(e);
        }
    }    

    public void setSender(JavaMailSender sender) {
        this.sender = sender;
    }

    public void setEngine(VelocityEngine engine) {
        this.engine = engine;
    }
}

Будучи хорошим программистом, я написал тестовые случаи для разных сценариев, чтобы убедиться, что все работает правильно. Один из моих случаев, когда указано вложение, но самого файла нет, в частности

@Test(expected=MailException.class)
public void testSend_MissingAttachment() throws IOException, MailException {
    // create new object
    MailSenderVelocity testSender = new MailSenderVelocity();
    testSender.setEngine(engine);
    testSender.setSender(sender);

    // assign properties
    String subject = "testSend_MissingAttachment";
    String template = "simple.vm";
    Map<Object, Object> model = new HashMap<Object, Object>();
    model.put("user", "User");
    boolean isHtml = true;
    Map<String, Resource> attachments = new HashMap<String, Resource>();
    String file = "notext.txt";
    attachments.put(file, templateDirectory.createRelative(file));
    Map<String, Resource> inline = null;

    // send a message -- will fail because it won't find the file to attach
    testSender.send(this.to, this.from, subject, template, model, isHtml, attachments, inline);
}

Теперь тест приводит к ожидаемому исключению

org.springframework.mail.MailSendException: Failed messages: javax.mail.MessagingException: IOException while sending message;
nested exception is:
  java.io.FileNotFoundException: class path resource [com/company/mail/template/notext.txt] cannot be opened because it does not exist; message exception details (1) are:
 Failed message 1:
 javax.mail.MessagingException: IOException while sending message;
   nested exception is:
  java.io.FileNotFoundException: class path resource [com/company/mail/template/notext.txt] cannot be opened because it does not exist
  at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:625)
  at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:416)
  at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:340)
  at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:355)
  at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:344)
  at com.company.mail.MailSenderVelocity.send(MailSenderVelocity.java:103)
  at com.company.mail.MailSenderVelocity.send(MailSenderVelocity.java:53)
  at com.company.mail.MailSenderVelocityTest.testSend_MissingAttachment(MailSenderVelocityTest.java:136)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
  at java.lang.reflect.Method.invoke(Method.java:600)
  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
  at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
  at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:22)
  at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
  at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
  at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
  at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
  at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
  at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)
  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
  at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
  at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
  at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
  at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
  at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
  at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
  at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
  at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
 Caused by: java.io.FileNotFoundException: class path resource [com/company/mail/template/notext.txt] cannot be opened because it does not exist
  at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:158)
  at org.springframework.mail.javamail.MimeMessageHelper$1.getInputStream(MimeMessageHelper.java:1086)
  at javax.activation.DataHandler.writeTo(DataHandler.java:302)
  at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1350)
  at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:845)
  at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:361)
  at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:85)
  at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:881)
  at javax.activation.DataHandler.writeTo(DataHandler.java:314)
  at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1350)
  at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1683)
  at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:585)
  ... 38 more
 2010-11-11 13:50:30,261

Однако сообщение электронной почты по-прежнему отправляется указанному получателю от указанного отправителя. Все остальные элементы (тема, тело и т. д.) остаются пустыми. Как остановить отправку электронной почты, когда при создании электронной почты создается исключение.


person LostHisMind    schedule 11.11.2010    source источник


Ответы (1)


Интересно. Похоже, что внутренняя реализация Sun JavaMail допускает исключения, выдаваемые обработчиками вложений, и продолжает работать, несмотря ни на что.

Самое простое решение, которое я могу придумать, - это выполнить небольшую предварительную проверку ваших ресурсов вложений, например.

for (Entry<String, Resource> entry : inline.entrySet()) {
   entry.getValue().getInputStream(); // validate the resource - fails if not existing
   helper.addInline(entry.getKey(), entry.getValue());
}

Это с нетерпением проверит, что Resource доступен. Вы также можете использовать Resource.exists() для такого рода вещей, если хотите.

person skaffman    schedule 12.11.2010
comment
Это имеет смысл. Я изменил циклы в подготовительном модуле, чтобы они имели условие -- if (!entry.getValue().exists()) throw new MailException(attachment[ + entry.getKey() + ] не существует); -- перед добавлением файла, и он работает. Спасибо за предложение! - person LostHisMind; 12.11.2010