10 Replies Latest reply on Sep 10, 2010 9:31 AM by Michael Fetzer

    Logging sent Mail Messages

    Christian Decker Newbie

      Hi all,


      I want to be able to intercept and store mail messages that are sent through my web application for later reference. As I understand it the best way to get the rendered content of the message is to actually replace the Transport in the JavaMail session by a custom class that stores the content and then calls the original Transport, but so far I have been unable to do that:




      public class LogMailTransport extends SMTPTransport {
      
           public LogMailTransport(Session session, URLName urlname) {
                super(session, urlname);
                
                log.debug("Using log mail smtp transport layer.");
                System.out.println("Using log mail smtp transport layer.");
           }
           
           
           
           @Override
           public void sendMessage(Message message, Address[] addresses)
                     throws MessagingException, SendFailedException {
                
                super.sendMessage(message, addresses);
                
                log.debug("Sent message: " + message.getSubject() + "\n type: " + message.getContentType() + "\n mail id: " + mailManager.getMail().getId() + "\n");
                
           }
      
      }




      And to render the content and actually send it I use the following:


      Session javaMailSession = Session.getDefaultInstance(System.getProperties());
      
      // does not work. add this row to $JAVA_HOME/jre/lib/javamail.providers
      // protocol=smtp; type=transport; class=xyz.util.LogMailTransport; vendor=FGCZ;
      // (possibly also for smtps/xyz.util.LogMailSSLTransport)
      
      Provider p = new Provider(Type.TRANSPORT, "smtp", "xyz.util.LogMailTransport", "FGCZ", "1.0");
      javaMailSession.setProvider(p);
      
      Provider trans = javaMailSession.getProvider("smtp");
      Provider transSSL = javaMailSession.getProvider("smtps");
      
      log.debug("smtp transport: " + trans.getClassName() + "smtp ssl transport: " + transSSL.getClassName());
      
      ret = renderer.render(template);



      I actually made sure that it is printing my class but then the sendMessage function of my class is never called.


      Any idea as to why? Or is there a simpler solution to my problem?

        • 1. Re: Logging sent Mail Messages
          Nikolay Elenkov Master

          Turn on JavaMail debugging to see what's going on.

          • 2. Re: Logging sent Mail Messages
            Michael Fetzer Newbie

            Hi Nikolay


            JavaMail actually reports




            DEBUG: Providers Listed By Protocol: {
            imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Sun Microsystems, Inc], 
            imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Sun Microsystems, Inc], 
            mock=javax.mail.Provider[TRANSPORT,mock,org.jboss.seam.mock.MockTransport,JBoss Seam Integration Tests], 
            
            smtps=javax.mail.Provider[TRANSPORT,smtps,xyz.util.LogMailSSLTransport,FGCZ],
            
            pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Sun Microsystems, Inc], 
            pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Sun Microsystems, Inc], 
            
            smtp=javax.mail.Provider[TRANSPORT,smtp,xyz.util.LogMailTransport,FGCZ]}|#]
            




            which would imply (?) that our LogMail... class should be used, however 'sendMessage' is never called...


            Any ideas?

            • 3. Re: Logging sent Mail Messages
              Shervin Asgari Master

              Have you tried sending an event after the mail is sent, so you can store the message in whatever format you want?


              Something like:



              Name("someSeamComponent")
              public class Foo {
              
              @In(create=true)
              Renderer renderer;
              
              public void sendMessage(String message) {
                Events.instance().raiseEvent("sendingMail", message);
                renderer.render("email.xhtml");
              }
              }



              Then in your observer you store the message before sending it

              • 4. Re: Logging sent Mail Messages
                Christian Decker Newbie

                The Problem is that when you call the renderer it hasn't yet rendered the message yet, which means that the most you can get out is the template without any replacements and data in it. On the other hand the renderer automatically connects to the SMTP Transport and fires off the mail, so it doesn't return the rendered mail.

                • 5. Re: Logging sent Mail Messages
                  Shervin Asgari Master

                  Should still be very easy to do.


                  All you need to do is extend org.jboss.seam.faces.renderer which is the org.jboss.seam.ui.facelet.FaceletsRenderer class.




                  @Scope(ScopeType.STATELESS)
                  @BypassInterceptors
                  @Name("org.jboss.seam.faces.renderer")
                  @AutoCreate
                  public class MyFaceletsRenderer extends FaceletsRenderer {
                  
                      /**
                      * Render the viewId, anything written to the JSF ResponseWriter is
                      * returned 
                      */
                     @Override
                     public String render(final String viewId) 
                     {
                       
                       String mail = super().render(viewId);
                       // Now store the mail somewhere
                       Events.raiseEvent("storeMail", mail);
                       return mail;
                     }
                  }



                  • 6. Re: Logging sent Mail Messages
                    Shervin Asgari Master

                    It should be


                    super.render(viewId);



                    • 7. Re: Logging sent Mail Messages
                      Christian Decker Newbie

                      Strangely I always assumed that the render call would return a single string that would tell me whether the view was rendered correctly or not. But I never thought it would return the rendered content.


                      A quick debug session showed that in fact parts of the template are returned:




                      <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >



                      Which is not quite what I'd expected, but it's not even the complete solution since all the tags from the xmlns:m="http://jboss.com/products/seam/mail" are left out, which actually is the part I'm interested in (specifically the <m:body/>. Furthermore the <m:message/> element is the root element for the document so I won't be able to just duplicate the message content, which would be undesirable even if it were possible.

                      • 8. Re: Logging sent Mail Messages
                        Michael Fetzer Newbie

                        We (/I) have actually thought about this before since it is the main problem we are having here.


                        We want to log the emails we send to our users. We cannot just log the parameters for the mail templates since they might change over time. Therefore we want to just log the what we actually sent which is the output of the renderer... (which seems to be quite difficult to get)


                        Back to the first try.


                        It seems that Seam does not use JavaMailSession returned by Session.getDefaultInstance(System.getProperties() since before and after the call to the renderer, javaMailSession.getProvider("smtp") returns our provider.


                        How can we get the JavaMailSession that Seam is actually using?

                        • 9. Re: Logging sent Mail Messages
                          Nikolay Elenkov Master

                          Do you have an javamail.address.map file and if so, what's in it? If you don't have it, try adding one with the following contents:


                          rfc822=smtp
                          



                          I also noticed you have the Seam MockTransport installed, where does it come from? Seam may be using that if you have rfc822=mock in your  javamail.address.map file. Try removing the mock transport to simplify things a bit.


                          Seam builds a Properties on the fly and uses that to get the session, for details check org.jobss.seam.mail.MailSession.java.If you want to change things you can try to override the org.jboss.seam.mail.mailSession.


                          I've said this before, but if you need more control, don't use Seam Mail. Use JavaMail directly and save yourself some trouble.


                          HTH



                          • 10. Re: Logging sent Mail Messages
                            Michael Fetzer Newbie

                            This does not solve the problem. (It doesn't change anything... :-( )


                            I guess we will have to use JavaMail directly since it seems near impossible to get the output of a renderer. (Which means we cannot use the templating engine provided by Seam.)