You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@camel.apache.org by "Shenavai, Manuel" <ma...@sap.com.INVALID> on 2022/07/06 14:46:04 UTC

Mail Attachment not available after mail consumer

Hi everyone,

we are using the mail component (consumer) to poll emails and we found that mail-attachments without a filename are ignored. Is there any workaround to get attachment that don't have a name?

There is one client sending a mail containing an attachment (its of Content-Type: message/rfc822). For some reason, no filename is provided (see in the pseudo-mimemessage highlighted below). Due to missing filename, the attachment will not be set into the attachmentList (filename is null):
https://github.com/apache/camel/blob/main/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java#L353

Any ideas?

Best regards,
Manuel


MimeMessage:

Content-Type: multipart/mixed;
                        boundary="_004_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_"
[...]

--_004_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_
Content-Type: multipart/alternative;
                        boundary="_000_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_"

--_000_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

test

--_000_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_
Content-Type: text/html; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

[...]

--_000_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_--

--_004_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_
Content-Type: message/rfc822
Content-Disposition: attachment;
                creation-date="Wed, 06 Jul 2022 14:27:01 GMT";
                modification-date="Wed, 06 Jul 2022 14:27:01 GMT"

The attachment content

--_004_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_--

RE: Mail Attachment not available after mail consumer

Posted by Daniel Langevin <da...@shq.gouv.qc.ca>.
Hi,

message/rfc822 are NestedMessage !!!!.
So we implement a special route to process them. We extract 822  and save it on specific eml file

We using Camel 3.14.3 with blueprint bundles in OSGI Karaf 4.33


Here some code we made, hope it help you.

2 cases for 822

1- BODY Nested Mail, no TEXT in MAIL

<choice>
 <when><simple>${body} is "com.sun.mail.imap.IMAPNestedMessage"</simple> <!-- seulement msg822 en pieceJointe -->
       <setHeader name="zzBody">
          <simple> ( Impossible d'extraire le Corps du message, voir pièce jointe msg822 )</simple>
       </setHeader>
       <filter><simple>${properties:devlogFlag} == 'O' </simple>
          <log message="000 Null BODY: "/>
       </filter>
       <to uri="direct:sdiInsertBodyCourriel" />
       <to uri="direct:sdiExtractMsg822" />
 </when>

2- Multipart BODY
<when><simple>${body} is "javax.mail.internet.MimeMultipart"</simple>
       <filter><simple>${properties:devlogFlag} == 'O' </simple>
          <log message="000 BODY: Multipart"/>
       </filter>
       <to uri="direct:sdiExtractPJ" />
       <to uri="direct:sdiExtractBodyMPart" />
       <to uri="direct:sdiInsertBodyCourriel" />
       <to uri="direct:sdiExtractMsg822" />
       <setHeader name="zzSwitchlirePj">
          <groovy>
                zPjTemp       = new File( request.headers['zzTEMPPJ'] )
                zzPj          = zPjTemp.listFiles();
                if ( zzPj.length &gt; 0 ) { result="OUI"}
                     else { result="NON" }
          </groovy>
       </setHeader>
       <filter><simple>${properties:devlogFlag} == 'O' </simple>
               <log message="SwitchlirePj: ${header.zzSwitchlirePj} " />
       </filter>
       <filter><simple>${header.zzSwitchlirePj} == "OUI" </simple>
               <to uri="direct:sdiLirePjCourriel" />
       </filter>
</when>
.....
.....


<route id="rte.{{SYS.SHQ}}.ExtractBodyMPart" streamCache="true">
    <from uri="direct:sdiExtractBodyMPart"/>
     <log message="555 Extract BODY" />
       <setHeader name="zzBody">
       <groovy>
          part            = request.body.getBodyPart(0)
          //part            = request.getOriginalMessage().getContent().getBodyPart(0)
          def Jsoup       = new org.jsoup.Jsoup();
          def wlist(org.jsoup.safety.Whitelist basic ) {
              return new org.jsoup.safety.Whitelist()
                     .addTags(
                              "a", "b", "blockquote", "br", "cite", "code", "dd", "dl", "dt", "em",
                              "i", "li", "ol", "p", "pre", "q", "small", "span", "strike", "strong", "sub",
                              "sup", "u", "ul")
                     .addAttributes("a", "href")
                     .addAttributes("blockquote", "cite")
                     .addAttributes("q", "cite")
                     .addProtocols("a", "href", "ftp", "http", "https", "mailto")
                     .addProtocols("blockquote", "cite", "http", "https")
                     .addProtocols("cite", "cite", "http", "https")
              }

            if ( part.getContent().getClass().equals(com.sun.mail.imap.IMAPNestedMessage)) {
                 result = "( PAS DE CORPS DE MESSAGE / voir piece jointe ) ";
            }
            else if ( part.getContentType().toLowerCase().contains('html')) {
                     zbody   = part.getContent();
                     zbody   = Jsoup.clean(zbody,wlist()); // conserve seulement certains tags de bases
                     zbody   = zbody.replaceAll("&lt;a .*href=","")
                     zbody   = zbody.replaceAll("&gt;&lt;/a&gt;","")
                     result  = Jsoup.parse(zbody).wholeText(); // preserve CRLF
                    }
            else if ( part.getContent().getClass().equals(javax.mail.internet.MimeMultipart)) {
                    result = part.getContent().getBodyPart(0).getContent();
                    }
            else {
                 result = part.getContent();
                 }
       </groovy>
       </setHeader>
</route>


<route id="rte.{{SYS.SHQ}}.InsertBodyCourriel" streamCache="true">
    <from uri="direct:sdiInsertBodyCourriel"/>
    <doTry>
     ... insert in SQL Database
       <doCatch>
          <exception>org.springframework.jdbc.BadSqlGrammarException</exception>
          <exception>java.sql.SQLSyntaxErrorException</exception>
          <exception>java.sql.SQLException</exception>
          <exception>java.sql.SQLIntegrityConstraintViolationException</exception>
          <exception>java.lang.IllegalArgumentException</exception>   
       </doCatch>
      ...
      ...
    </doTry>
...
...
</route>




<route id="rte.{{SYS.SHQ}}.ExtractMsg822" streamCache="true">
<description>
=======================================================================
Permet d'extraire et d'écrire les parties messages/822 dans un fichier
Ce(s) fichier(s) seront par la suite inscrit dans la BD comme PJ_Courriel_nn.eml
=======================================================================
</description>

<from uri="direct:sdiExtractMsg822"/>
<filter><simple>${properties:devlogFlag} == 'O' </simple>
       <log message="777 Extract MSG822 ?" />
<filter/>
<setHeader name="zz822">
<groovy>
    zresult = 0
    if ( request.body.getClass().equals(com.sun.mail.imap.IMAPNestedMessage)) {
       zHeaders=""
       crlf="\r\n"
       headerEnum = request.body.getAllHeaders();
       while (headerEnum.hasMoreElements()) {
         header = headerEnum.nextElement();
         name = header.getName();
         <!-- Anonymise les information de securite, adresse IP des serveurs Internes -->
         value = header.getValue().replaceAll('10.100.','192.168.');
         zHeaders = zHeaders + name +": " + value + "\r\n"
       }
       mail822filename = request.headers['zzTEMP822']+"PJ_Courriel_1.eml"
       mailoriginal = new File(mail822filename);
       mailoriginal.write(zHeaders+crlf);
       mailoriginal.append(request.body.getContentStream().getText()+crlf);
       zresult = zresult + 1;
    }  else {
            mimeMultipart = request.body
            partCount = mimeMultipart.getCount();
            for (i = 0; i != mimeMultipart.getCount(); i++) {
                ii = i;
                bodyPart = mimeMultipart.getBodyPart(i);
                if (bodyPart.isMimeType("message/rfc822")) {
                    zresult = zresult + 1;
                    mail822filename = request.headers['zzTEMP822']+"PJ_Courriel_" + zresult + ".eml"
                    bodyPart.getContent().writeTo(new FileOutputStream(new File(mail822filename)));
                }
            }
          //  if ( zresult &gt; 1){  zresult = zresult - 1; } // replace le bon nombre de PJ extraite apres la LOOP
       }
   result = zresult
</groovy>
</setHeader>
<filter><simple>${properties:devlogFlag} == 'O' </simple>
        <log message="777 N822= ${header.zz822}" />
</filter>
<setHeader name="zzLoop"> <constant>0</constant></setHeader>
<loop doWhile="true"><simple>${header.zzLoop} != ${header.zz822}</simple>
<log message="Loop ? ${header.zzLoop} = ${header.zz822}" />
    <setHeader name="zzLoop"><simple>${header.zzLoop}++</simple></setHeader>
    <setHeader name="zzPJ" ><groovy>new File(request.headers['zzTEMP822']+"PJ_Courriel_"+request.headers['zzLoop']+".eml").bytes</groovy></setHeader>
    <setHeader name="utlRecCourrielPjContentType" ><constant>message/rfc822</constant></setHeader>
    <setHeader name="utlNomPj" ><simple>PJ_Courriel_${header.utlNoSeqCommunication}_${header.zzLoop}.eml</simple></setHeader>
    <setHeader name="zzTypeCode"><constant>REGUL</constant></setHeader>
    <to uri="direct:sdiInsertPjCourriel" />
</loop>
</route>


<route id="rte.{{SYS.SHQ}}.LirePjCourriel" streamCache="true">
  <from uri="direct:sdiLirePjCourriel"/>
  <setHeader name="zzPJtmp">
  <groovy>
    zPjTemp     = new File( request.headers['zzTEMPPJ'] )
    zz          = zPjTemp.listFiles();
    zresult     = ""
    for (int i = 0; i &lt; zz.length; i++) {
       zresult = zresult + zz[i].getName()+","
       }
    zresultArray = zresult.tokenize(',');
    result       = zresultArray;
  </groovy>
  </setHeader>
  <setBody><simple>${header.zzPJtmp}</simple></setBody>
  <split><tokenize token="," />
     <setHeader name="utlNomPjEncode" ><simple>${header.zzPJtmp[${header.CamelSplitIndex}]}</simple></setHeader>
     <setHeader name="utlNomPj" ><groovy>
         // replace le nom de fichier si contient Caracteres Speciaux (rfc5987)
        def MimeUtility = new javax.mail.internet.MimeUtility();
        result = MimeUtility.decodeText(request.headers['utlNomPjEncode']);
     </groovy></setHeader>
     <setHeader name="zzTypeCode"><constant>REGUL</constant></setHeader>
     <setHeader name="utlRecCourrielPjContentType" >
        <groovy>
          zFile       = new File( request.headers['zzTEMPPJ']+request.headers['utlNomPjEncode'] )
          result      = java.nio.file.Files.probeContentType(zFile.toPath())
        </groovy>
     </setHeader>
     <setHeader name="zzPJ"><groovy>new File(request.headers['zzTEMPPJ']+request.headers['utlNomPjEncode']).bytes</groovy></setHeader>
     <to uri="direct:sdiInsertPjCourriel" />
   </split>
</route>




Daniel Langevin


-----Message d'origine-----
De : Shenavai, Manuel <ma...@sap.com.INVALID> 
Envoyé : 6 juillet 2022 10:46
À : users@camel.apache.org
Objet : Mail Attachment not available after mail consumer

Hi everyone,

we are using the mail component (consumer) to poll emails and we found that mail-attachments without a filename are ignored. Is there any workaround to get attachment that don't have a name?

There is one client sending a mail containing an attachment (its of Content-Type: message/rfc822). For some reason, no filename is provided (see in the pseudo-mimemessage highlighted below). Due to missing filename, the attachment will not be set into the attachmentList (filename is null):
https://can01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fapache%2Fcamel%2Fblob%2Fmain%2Fcomponents%2Fcamel-mail%2Fsrc%2Fmain%2Fjava%2Forg%2Fapache%2Fcamel%2Fcomponent%2Fmail%2FMailBinding.java%23L353&amp;data=05%7C01%7Cdaniel.langevin%40shq.gouv.qc.ca%7C33e11d4b7fba4be7c80c08da5f5e55b9%7C8377d97d01504e07b82ad67c55dc2c05%7C0%7C0%7C637927157485289751%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C2000%7C%7C%7C&amp;sdata=o%2FIuiTCT%2F4YJDqltQrmv8D3QLA7KQ%2B%2F4DsmRt%2FqsiJ8%3D&amp;reserved=0

Any ideas?

Best regards,
Manuel


MimeMessage:

Content-Type: multipart/mixed;
                        boundary="_004_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_"
[...]

--_004_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_
Content-Type: multipart/alternative;
                        boundary="_000_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_"

--_000_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

test

--_000_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_
Content-Type: text/html; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

[...]

--_000_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_--

--_004_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_
Content-Type: message/rfc822
Content-Disposition: attachment;
                creation-date="Wed, 06 Jul 2022 14:27:01 GMT";
                modification-date="Wed, 06 Jul 2022 14:27:01 GMT"

The attachment content

--_004_AM9PR02MB74107D2A35952A65E4234BBBE8809AM9PR02MB7410eurp_--