Mail Plugin

grails-mail IllegalStateException when sending 'body' mail from grails-springws endpoint

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Minor Minor
  • Resolution: Fixed
  • Affects Version/s: None
  • Fix Version/s: Grails-Mail-1.0
  • Component/s: None
  • Labels:
    None
  • Environment:
    WinXP, Grails 1.1.1, plugins.mail=0.7.1, plugins.springws=0.2.3

Description

I have a grails-springws endpoint that is attempting to send an email using the grails-mail plugin. grails-mail supposedly supports use of a gsp to produce the message body even when there is no current request.

In my endpoint I successfully send a message using the 'html' format as follows and the endpoint will operate correctly:

def mailService
...
        mailService.sendMail {
            to 'you@example.com'
            subject 'A subject'
            html '<b>Hello</b> World'
        }

But if I use the 'body' format, which uses an absolute path to a gsp as follows:

def mailService
...
        mailService.sendMail {
            to 'you@example.com'
            subject 'A subject'
            body view:'/myController/mail/myTemplate', model:['myInstance':myInstance]
        }

... the email is sent, but the endpoint fails:

2009-09-25 16:44:47,415 [17613323@qtp0-33] ERROR mortbay.log  - /my-project/services/MyRequest/MyRequest.wsdl
java.lang.IllegalStateException: WRITER
        at org.mortbay.jetty.Response.getOutputStream(Response.java:564)
        at javax.servlet.ServletResponseWrapper.getOutputStream(ServletResponseWrapper.java:112)
        at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$6.create(GrailsPageResponseWrapper.java:137)
        at com.opensymphony.module.sitemesh.filter.RoutableServletOutputStream.getDestination(RoutableServletOutputStream.java:35)
        at com.opensymphony.module.sitemesh.filter.RoutableServletOutputStream.write(RoutableServletOutputStream.java:118)
        at org.springframework.ws.transport.TransportOutputStream.write(TransportOutputStream.java:60)

It would appear that the mailService is writing its output in such a way that it is corrupting the output stream being used by the endpoint.

Activity

Hide
Michael Legart added a comment -

I see the exactly same thing with a service exposed via the CXF plugin.

Show
Michael Legart added a comment - I see the exactly same thing with a service exposed via the CXF plugin.
Hide
Zachary Schneider added a comment -

Would love to see this fixed. Having HTML sitting as a string in my service is dirty

Show
Zachary Schneider added a comment - Would love to see this fixed. Having HTML sitting as a string in my service is dirty
Hide
Zachary Schneider added a comment -

Issue still exists in grails 1.1.2

Show
Zachary Schneider added a comment - Issue still exists in grails 1.1.2
Hide
Zachary Schneider added a comment -

Referenced here:
http://old.nabble.com/mime.DefaultAcceptHeaderParser-No-configured-mime-types-found-for-Accept-header-in-Mail-Plugin-td19975623.html

Wrapping the sendMail closure in a thread is a work around, I am unable to figure out why. But I am speculating the culprit is GrailsPageResponseWrapper probably due to the output buffer juggling that is happening in the mail plugin.

So:

def t = new Thread() {
	sendMail {
		to user.email
                from 'email@emails.com'
                subject 'Subject'
                body (view:'/mail/myTemplate', model[user:user])
	}
}
t.start()
Show
Zachary Schneider added a comment - Referenced here: http://old.nabble.com/mime.DefaultAcceptHeaderParser-No-configured-mime-types-found-for-Accept-header-in-Mail-Plugin-td19975623.html Wrapping the sendMail closure in a thread is a work around, I am unable to figure out why. But I am speculating the culprit is GrailsPageResponseWrapper probably due to the output buffer juggling that is happening in the mail plugin. So:
def t = new Thread() {
	sendMail {
		to user.email
                from 'email@emails.com'
                subject 'Subject'
                body (view:'/mail/myTemplate', model[user:user])
	}
}
t.start()
Hide
Andrew Pietsch added a comment - - edited

I'm also getting this when sending emails from a GWT Action handler. I too would love to see this fixed, having to put HTML in code is ugly.

Show
Andrew Pietsch added a comment - - edited I'm also getting this when sending emails from a GWT Action handler. I too would love to see this fixed, having to put HTML in code is ugly.
Hide
Lari Hotari added a comment -

This might be caused by org.codehaus.groovy.grails.web.servlet.GroovyPageWritable that changes the state of the response.

if(!contentTypeAlreadySet)  {
                response.setContentType(metaInfo.getContentType()); // must come before response.getWriter()
            }

It might be possible to workaround this problem by "binding" a MockResponse to the current thread and by calling WrappedResponseHolder.setWrappedResponse(mockResponse) and returning the state after rendering the mail template. This change would have to be done in the mail plugin (src/groovy/org/grails/mail/MailMessageBuilder.groovy , renderMailView method).

This problem might be related to the feature request GRAILS-3818 .

Show
Lari Hotari added a comment - This might be caused by org.codehaus.groovy.grails.web.servlet.GroovyPageWritable that changes the state of the response.
if(!contentTypeAlreadySet)  {
                response.setContentType(metaInfo.getContentType()); // must come before response.getWriter()
            }
It might be possible to workaround this problem by "binding" a MockResponse to the current thread and by calling WrappedResponseHolder.setWrappedResponse(mockResponse) and returning the state after rendering the mail template. This change would have to be done in the mail plugin (src/groovy/org/grails/mail/MailMessageBuilder.groovy , renderMailView method). This problem might be related to the feature request GRAILS-3818 .
Hide
Lari Hotari added a comment -

I looked into this a little further while investigating GRAILS-6049

This line in MailMessageBuilder

def originalOut = requestAttributes.getOut()

calls GrailsWebRequest.getOut :

/**
	 * @return the out
	 */
	public Writer getOut() {
		Writer out = attributes.getOut(getCurrentRequest());
		if(out ==null)
			try {
				return getCurrentResponse().getWriter();
			} catch (IOException e) {
				throw new ControllerExecutionException("Error retrieving response writer: " + e.getMessage(), e);
			}
		return out;
	}

This calls response.getWriter() if webRequest.out hasn't been set before.

Show
Lari Hotari added a comment - I looked into this a little further while investigating GRAILS-6049 This line in MailMessageBuilder
def originalOut = requestAttributes.getOut()
calls GrailsWebRequest.getOut :
/**
	 * @return the out
	 */
	public Writer getOut() {
		Writer out = attributes.getOut(getCurrentRequest());
		if(out ==null)
			try {
				return getCurrentResponse().getWriter();
			} catch (IOException e) {
				throw new ControllerExecutionException("Error retrieving response writer: " + e.getMessage(), e);
			}
		return out;
	}
This calls response.getWriter() if webRequest.out hasn't been set before.
Hide
Luke Daley added a comment -

Resolved in the pending 1.0 version, we no longer touch the active http response.

Show
Luke Daley added a comment - Resolved in the pending 1.0 version, we no longer touch the active http response.

People

Vote (4)
Watch (5)

Dates

  • Created:
    Updated:
    Resolved: