james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Mark Daring" <cog...@chello.at>
Subject Re: Merge Status
Date Fri, 12 Mar 2004 22:26:04 GMT
----- Original Message -----
From: "Noel J. Bergman" <noel@devtech.com>
To: "James Developers List" <server-dev@james.apache.org>
Sent: Thursday, March 11, 2004 9:54 PM
Subject: RE: Merge Status

>     public void addHeader(String name, String value)
>       throws MessagingException {
>         if (message == null) {
>             loadMessage();
>         }
>         modified = true;
>         headers.addHeader(name, value);
>         message.addHeader(name, value);
>     }
> The message is loaded as soon as we call addHeader.  That is part of what
> meant when I said that MimeMessageWrapper needs work.

something like this worked for me:
for example LocalDelivery:
    public void service(Mail mail) throws MessagingException {
            try {
                // Add qmail's de facto standard Delivered-To header
              // Prevent loading MimeMessage into memory
              if (message instanceof mailsec.MimeMessageWrapper)

                message.addHeader("Delivered-To", recipient.toString());

                 saveChanges() sets saved = true; modified = true; und calls
                 saved in MimeMessage.writeto(OutputStream,...) indicates
whether saveChanges() should be called

                 modified = true calls BodyPart.writeto(...) for encoding,
instead of writing the raw content to the outputstream
                 updateHeaders() calls BodyPart.updateHeaders(this) which
will call the encoding routines to determine the "Content-Transfer-Encoding"

                BUT if we already know the encoding because we havent added
anything that needs different encoding we can save saveChanges() :-)
                By the way if we add a header we have to take care of
encoding ourself - see javadocs!!!

//                localMessage.saveChanges();

                // put mail into inbox-repository
                if (getMailetContext().storeMail(mail.getSender(),
recipient, (MailImpl)mail)) {
                  if (!anonym) {
                    reporter.store((MailImpl)mail, null,Mail.DELIVERED);
            } catch (Exception ex) {


 * The Internet headers in memory for the wrapper only
 * No affect on the message
  MailHeaders wheaders = null;

   * Adds a Header to the wrapper only. The original MimeMessage is not
   * .writeTo(OutputStream headerOs, OutputStream bodyOs, String[]
ignoreList) will write this
   * header into the outputstream.
   * Purpose: Prevent loading the MimeMessage into memory.
   * @param name
   * @param value
   * @throws MessagingException
  public void addWrapperHeader(String name, String value) throws
MessagingException {
  if (wheaders == null) {
    wheaders = new MailHeaders();
  wheaders.addHeader(name, value);

  public void writeTo(OutputStream headerOs, OutputStream bodyOs) throws
IOException, MessagingException {
    writeTo(headerOs, bodyOs, new String[0]);

  public void writeTo(OutputStream headerOs, OutputStream bodyOs, String[]
ignoreList) throws IOException, MessagingException {
    if (message == null || !isModified()) {
      //We do not want to instantiate the message... just read from source
      //  and write to this outputstream

      //First handle the headers

      InputStream in = source.getInputStream();
      try {
        if (headerOs != null) {
          InternetHeaders iheaders = new InternetHeaders(in);

          //InternetPrintWriter adds "\r\n" to print(...)
          PrintWriter pos = new InternetPrintWriter(new BufferedWriter(new
OutputStreamWriter(headerOs), 512), true);
          for (Enumeration e =
iheaders.getNonMatchingHeaderLines(ignoreList); e.hasMoreElements(); ) {
            String header = (String)e.nextElement();
          // Write WrapperHeaders (no affect on message - only hold in
memory) for  our outputstream
          if (wheaders != null)
            for (Enumeration e =
wheaders.getNonMatchingHeaderLines(ignoreList); e.hasMoreElements(); ) {
              String header = (String)e.nextElement();
        if(bodyOs != null)
          copyStream(in, bodyOs);
      } finally {
    } else {
      writeTo(message, headerOs, bodyOs, ignoreList);

> > > Yeah, I would say more than just an individual header, but also
> > > individual message parts.  For example, you should be able to add a
> > > text/html footer to a message with a big image/zip attachment and not
> > > have to load that image/zip attachment into memory.
> > That´s also possible as long as no content is added that need encoding!
> > If you dont believe, try it, especially if you intend just u write back
> > "this doesnt work" without verification!
> How do you add it without loading?  Any of the JavaMail methods that
> the MimeMessage require it to be loaded.

I dont know how many IO or database operations James needs to insert an
incoming mail into a repository ( I guess 4 to 6 ) but
in any case too many. SMTPHandler stores the mail indepentendly of size as
file - which is the way to do it - and thats all we need if the rep is a
filestore, as a move (rename) operation would be satisfactory. On the other
hand if the database (as rep) has "problems" with BLOBs - like MySQL - mails
of a certain size should also be moved to a file-rep and not be stored in
the database, which makes James faster. And when it comes to size memory is
the next issue.

I allways breaked on the line that loads the mail into mem and step by step
eliminated all code that caused this. Now after mail is received and stored
as file it goes into the spooler, the manager, the processor, the mailets
and is never loaded entirely (only headers).

If you study the writeTo-method above you ll see that after InternetHeaders
is created, the streamposition is at the beginning of the body of the mail,
so a good place to insert the boundary of a MimeMultipart-wrapper for
example (or in the header case our custom headers), next write the orig mail
and finish with a private footer and the closing boundary again.
Or lets say read the first boundary of a Multipart then read the lengths of
the boundary + 3 ahead to the end of the mail and insert custom content
before. But
remember to change the headers appropriately as a new boundary is used.


To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org

View raw message