1 2 Previous Next 15 Replies Latest reply on Aug 10, 2011 2:23 AM by sivalingam.sivasuthan

    Seam email resend on exception or error

    tathagat

      Dear all.


      I use seam email and it works like a charm.


      But (there is always a but!) sometimes (for example when the SMTP server is down) email is not sent.


      What are my options in this case? How (and where) can I store the failed email and how can I resend it?


      Thanks very much in advance


      Tathagat

        • 1. Re: Seam email resend on exception or error
          gaborj



          • One option is that you define a mail-queue as JMS queue, put your messages into the queue. The sender then checks SMTP server status before sending messages from the queue. If your SMTP is down your queue is getting filled with messages when it recovers after outage your messages are delivered in the order they were sent, this queue is persistent so you never loose msg...







          • Of course similar processing can be implemented using database where you save the state of your messages and you run a scheduler e.g. Quartz with some short interval as sender (I think there is an asynchronous processor in mail example)...







          • Or you can combine these two above



          • 2. Re: Seam email resend on exception or error
            tathagat

            Thank you for your reply!
            I think databbase AND quartz approach would be best to guarantee success against SMTP failure and between restarts.


            Now the question is - How do I save the state of my email message in database?


            I send email using the following code (from seam docs):


            Contexts.getEventContext().set("emailInfo", infoNeededForTemplate);
            renderer.render(template);



            Thanks again in advance.


            Cheers
            T

            • 3. Re: Seam email resend on exception or error
              kapitanpetko

              Tathagat Tathagat wrote on Apr 18, 2010 23:15:


              I think databbase AND quartz approach would be best to guarantee success against SMTP failure and between restarts.

              Now the question is - How do I save the state of my email message in database?


              This has been asked before, search the forum. In general:



              • if you want more control, use JavaMail directly

              • if you do insist on using Seam mail, install your own Transport that saves the mail to DB before sending.



              HTH

              • 4. Re: Seam email resend on exception or error
                tathagat

                Great. Thanks so much :).


                In the end I wrote my own transport which saves the email in the DB.


                Cheers

                • 5. Re: Seam email resend on exception or error
                  tathagat

                  May be I spoke too soon :).


                  In my custom Transport I do the following (overiding sendMessage)




                       public void sendMessage(Message message,
                              Address[] addresses) {
                            try {
                                 // saving in DB
                                 // get the bytes from message and save in DB or do whatever
                                 
                                 super.sendMessage(message, addresses);
                                 logger.debug("sendMessage: " + this.getLastReturnCode());
                            } catch (SendFailedException e) {
                                 logger.error("sendMessage", e);
                            } catch (MessagingException e) {
                                 logger.error("sendMessage", e);
                            } catch (IOException e) {
                                 // TODO Auto-generated catch block
                                 e.printStackTrace();
                            }
                       }



                  This works fine.


                  Now to test, I passed in the wrong password from components.xml



                  <mail:mail-session host="smtp.gmail.com" port="465" ssl="true" username="USERNAME" password="WRONG PASSWORD"/>



                  At this point, my code throws exception even before it goes inside sendMessage.


                  Exception when renderer.render(template) is called


                  javax.faces.FacesException: failed to connect
                  Caused by: javax.mail.AuthenticationFailedException: failed to connect



                  So again, I do not have access to the message object to persist. Is there a way around this problem?


                  Thanks again


                  Cheers
                  T

                  • 6. Re: Seam email resend on exception or error
                    kapitanpetko

                    I don't have the code here, but maybe Seam's MailSession tries to authenticate first? Hit it with the debugger to see where it fails. Are you sure your Transport is installed properly?


                    • 7. Re: Seam email resend on exception or error
                      tathagat

                      Thanks for the hint!


                      Doing debugging now - will keep you posted.


                      Yes, when there are no errors -  my debug statements in custom Transport get printed.


                      Thanks a ton :).


                      Cheers
                      T

                      • 8. Re: Seam email resend on exception or error
                        tathagat

                        Alright!
                        After some debugging I found out that the method connect() was being called in javax.mail.Service somewhere down the line before sendMessage was called.


                        So I did the following:
                        In my custom Transport override connect() method




                             public void connect() {
                                  logger.debug("connect: DO NOTHING!");
                             }



                        and in public void sendMessage(Message message, Address[] addresses) (also in my custom Transport) I called super.connect() before super.sendMessage(message, addresses).


                        Doing this I have a handle to message no matter what goes wrong.


                        I hope this helps someone and I hope I don't find another problem :).


                        Thanks for all the help!


                        Cheers
                        T

                        • 9. Re: Seam email resend on exception or error
                          tathagat

                          Hoping didn't help :D. Got another problem.


                          I user hibernate session with tomcat for persistence.
                          So I use in my classes:


                          @In Session managedHibernateSession;



                          which is defined in my components.xml.


                          It works fine everywhere, except when I try to use it in my Custom Transport.


                          @Scope(ScopeType.APPLICATION)
                          public class CustomTransport extends SMTPSSLTransport {
                               @In(create=true,value="managedHibernateSession") org.hibernate.Session managedHibernateSession;



                          managedHibernateSession is always null!


                          Any guesses why? I tried different scopes on the class (although I have another class with Application scope and it works fine there).


                          Thanks in advance.


                          Cheers
                          T

                          • 10. Re: Seam email resend on exception or error
                            tathagat

                            Also, what's strange is:


                                 @Create
                                 public void create() {
                                      logger.debug("Creating Custom Transport");
                                 }



                            This code is never being called in my CustomTransport class.


                            Cheers
                            T

                            • 11. Re: Seam email resend on exception or error
                              kapitanpetko

                              I don't think the transport can be a Seam component, hence not @Create-ing and @In-jecting. Instantiate your Session without using Seam.

                              • 12. Re: Seam email resend on exception or error
                                tathagat

                                Thanks for the hint.


                                I could not figure out how to instantiate my own Session (right now Seam does it reading from components.xml)


                                So I created following properties in my CustomTransport



                                     private Message message;
                                     private Address[] addresses;
                                     private int returnCode;




                                and changed the sendMessage method to fill them.



                                     public void sendMessage(Message _message, Address[] _addresses) {
                                          setMessage(_message);
                                          setAddresses(_addresses);
                                          try {
                                               super.connect();
                                               super.sendMessage(_message, _addresses);
                                          } catch (SendFailedException e) {
                                               logger.error("sendMessage", e);
                                          } catch (MessagingException e) {
                                               logger.error("sendMessage", e);
                                          }
                                          finally {
                                               returnCode = this.getLastReturnCode();
                                          }
                                     }




                                This also required the constructor to be changed




                                     private static CustomTransport customTransport ;
                                     public CustomTransport(Session session, URLName urlname) {
                                          super(session, urlname);
                                          customTransport = this;
                                     }



                                and a getInstance method to be created




                                     public static CustomTransport getInstance() {
                                          return customTransport ;
                                     }



                                Now after sending an email, I can fetch the values from my CustomTransport and save them in the DB.


                                Thanks again for all the help :).


                                P.S. May be someone can tell me how to instantiate Hibernate Session object manually?


                                Cheers
                                T

                                • 13. Re: Seam email resend on exception or error
                                  kapitanpetko

                                  Good that it worked out, but consider what happens if two messages are sent more or less simultaneously. You instantiate a Session the usual way: create a SesssionFactory, then call openSession.


                                  • 14. Re: Seam email resend on exception or error
                                    tathagat

                                    abso-freakin-lutely right!


                                    I was worrying about that but did not have another solution at hand.


                                    I still could not get a Session using SessionFactory (tried HibernateUtil). Always one exception or the other.


                                    But in the end this worked


                                    org.hibernate.Session hibernateSession = (org.hibernate.Session) Component.getInstance("managedHibernateSession");



                                    Now all is good :).


                                    Thanks again so much for all the help.


                                    Cheers
                                    T

                                    1 2 Previous Next