This document shows how to override the default Alfresco
email handler. This document assumes
you already have Alfresco 4.0 Community Edition installed you have inbound
email already configured.
If you do not have this done you can look at my other guide Alfresco_4_Install_on_ubuntu_12_04_and_make_folder_emailable
For this particular install I am using Alfresco 4.0.e on
Ubuntu 12.04
Why?
Why would you want to override the default inbound email
handler?
Well, I am sure you can think of many reasons, for me I had
a project for a company that would forward emails from gmail and send them all
to the same folder. The custom email
handler would check for an attachment and based on its name save it to a
different folder. Also it only saved
the attached file and not the email itself.
Tomcat alfresco settings
My install of tomcat is located at /opt/tomcat
The current inbound e-mail settings can be found at
/opt/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/subsystems/email/InboundSMTP
In the file inboundSMTP-context.xml
According to http://wiki.alfresco.com/wiki/Inbound_SMTP_Email_Server_Configuration#Configuration
[2] you should be able to copy this folder over to / opt/tomcat/shared/classes/alfresco/extension/subsystems/email/InboundSMTP/inboundSMTP-context.xml and have it override the default alfresco
XML file, but I can never get this to
work for some reason. I merely copied it
over, but it never overrides, if anyone has any advice on this I would love to
hear it.
So since I can’t override I just update the default one
Update the default
file
> sudo vi +135 /opt/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml
|
Edit this
<bean
id="folderEmailMessageHandler"
parent="emailMessageHandlerBase"
class="org.alfresco.email.server.handler.FolderEmailMessageHandler"
>
|
To this
<bean
id="folderEmailMessageHandler"
parent="emailMessageHandlerBase"
class="com._10x13.alfresco.email.CustomFolderEmailMessageHandler"
>
|
Create your custom class and install it
Now that the default
inbound email handler is overridden a new class needs to be created to replace
it. In the prior section we are looking
for a class named com.10x13.alfresco.email.CustomFolderEmailMessageHandler . Therefore
we need to create a program with this same name.
Now before I go too
far I want to say this example overrides folderEmailMessageHandler which
only overrides the inbound email handler for folders. There are other handlers for other objects
in alfresco.
Before we get into
programming it’s probably a good idea to update the logger so we can log some
messages. To do this you need to edit /opt/tomcat/webapps/alfresco/WEB-INF/classes/log4j.properties
> sudo
vi /opt/tomcat/webapps/alfresco/WEB-INF/classes/log4j.properties
|
I added this to the
end of the file
##Custom
Logger
log4j.logger.com._10x13=INFO, CUSTOM,
CUSTOMSTDOUT
log4j.appender.CUSTOM=org.apache.log4j.RollingFileAppender
log4j.appender.CUSTOM.File=/opt/tomcat/logs/emailhandler.log
log4j.appender.CUSTOM.MaxFileSize=50MB
#
Keep ten backup file
log4j.appender.CUSTOM.MaxBackupIndex=10
log4j.appender.CUSTOM.layout=org.apache.log4j.PatternLayout
log4j.appender.CUSTOM.layout.ConversionPattern=[%p]::[%d]::"%m"::
%C %n
log4j.appender.CUSTOMSTDOUT=org.apache.log4j.ConsoleAppender
log4j.appender.CUSTOMSTDOUT.DatePattern='.'yyyy-MM-dd
log4j.appender.CUSTOMSTDOUT.layout=org.apache.log4j.PatternLayout
log4j.appender.CUSTOMSTDOUT.layout.ConversionPattern=[%p]::[%d]::"%m"::
%C %n
|
Now for the program!
I am just going to use command line javadoc and jar to create the program, feel
free to use your IDE of choice to do this in a more appropriate way.
To better understand
the default Email hander you can check out its javadoc at http://dev.alfresco.com/resource/docs/java/repository/org/alfresco/email/server/handler/FolderEmailMessageHandler.html [1]
First a simple program
First
make a simple program that will overwrite the default folder email program and
just output a log message.
Run the
following command
> cd
> mkdir
MyProgram
> cd
MyProgram
> mkdir
dist
> mkdir
–p com/_10x13/alfresco/email
> vi
com/_10x13/alfresco/email/CustomFolderEmailMessageHandler.java
|
Here is
the program
package
com._10x13.alfresco.email;
import
org.alfresco.email.server.handler.FolderEmailMessageHandler;
import
org.apache.log4j.Logger;
import
org.alfresco.service.cmr.repository.NodeRef;
import
org.alfresco.service.cmr.email.EmailMessage;
public
class CustomFolderEmailMessageHandler extends FolderEmailMessageHandler {
private Logger log =
Logger.getLogger("com._10x13");
public void processMessage(NodeRef
nodeRef, EmailMessage message){
log.info("This is a test of my
Email override Tool");
super.processMessage(nodeRef, message);
}
}
|
To compile to file we need to include several jar files
these jar files are
alfresco-data-model-4.0.e.jar
alfresco-repository-4.0.e.jar
log4j-1.2.15.jar
alfresco-data-model-4.0.e.jar
is located at
/opt/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-data-model-4.0.e.jar
alfresco-repository-4.0.e.jar is located at
/opt/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-repository-4.0.e.jar
log4j-1.2.15.jar is
located at
/opt/tomcat/webapps/alfresco/WEB-INF/lib/log4j-1.2.15.jar
To compile your
program via the command line and include these jar files run this command
> javac
-d dist -cp
/opt/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-repository-4.0.e.jar:/opt/tomcat/webapps/alfresco/WEB-INF/lib/log4j-1.2.15.jar:/opt/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-data-model-4.0.e.jar ./com/_10x13/alfresco/email/CustomFolderEmailMessageHandler.java
|
This will place the
.class file in the dist directory.
Now create the jar
file
> jar
cfv custom-email.jar -C dist/ .
|
copy the jar file to
tomcat
> sudo cp custom-email.jar
/opt/tomcat/webapps/alfresco/WEB-INF/lib/
|
restart tomcat
> sudo /etc/init.d/tomcat stop
> sudo /etc/init.d/tomcat start
|
After it reboots
send an email, but first tail the email log
> sudo tail -f
/opt/tomcat/logs/emailhandler.log
|
now send an email
into your system (of course this will
only work if you had your alfresco set up to accept inbound emails before
starting this guide, this guide does not cover that) in my case I set it up to accept emails to
inbox. So since this is an Amazon
server I set an email to inbox@ec2-23-11-12.compute-1.amazonaws.com
Now if you look at the folder you emailed into (in my case its in share)
The e-mail is there.
Then look at the log you tailed and you should see
Now that is all well and good but all we really accomplished
was to write a log message out. Let’s
do something real.
Here is the code updated to do something interesting
package
com._10x13.alfresco.email;
import
java.io.InputStream;
import
org.alfresco.email.server.handler.FolderEmailMessageHandler;
import
org.apache.log4j.Logger;
import
org.alfresco.service.cmr.repository.NodeRef;
import
org.alfresco.service.cmr.email.EmailMessage;
import
org.alfresco.service.cmr.email.EmailMessagePart;
import
org.alfresco.service.cmr.repository.MimetypeService;
import
org.alfresco.service.cmr.repository.NodeRef;
import
org.alfresco.service.namespace.QName;
public
class CustomFolderEmailMessageHandler
extends
FolderEmailMessageHandler {
private Logger log =
Logger.getLogger("com._10x13");
public void processMessage(NodeRef
folderNodeRef, EmailMessage message){
String toAddress = message.getTo();
String fromAddress =
message.getFrom();
String subject =
message.getSubject();
MimetypeService mimetypeService =
getMimetypeService();
InputStream contentIs;
NodeRef contentNodeRef;
String mimeType;
log.info("An Email was sent to:
" + toAddress);
log.info("An Email was sent
from: " + fromAddress);
log.info("An Email was sent with
the subject line of: " + subject);
for(EmailMessagePart attachment:
message.getAttachments()) {
//Skip saving the email as an
html file
if(!attachment.getFileName().startsWith(subject)){
log.info("attached file
is named: " + attachment.getFileName()
+
"And Has a size of: " + attachment.getSize() + " Bytes");
contentIs =
attachment.getContent();
mimeType = mimetypeService.guessMimetype(attachment.getFileName());
contentNodeRef =
addContentNode(getNodeService(),
folderNodeRef, attachment.getFileName(), true);
writeContent(contentNodeRef,
contentIs, mimeType,
attachment.getEncoding());
}
}
}
}
|
A lot of new imports on this one here is a line by line on the important ones
and where to find their javadocs
import
org.alfresco.service.cmr.repository.NodeRef;
import
org.alfresco.service.cmr.email.EmailMessage;
import org.alfresco.service.cmr.email.EmailMessagePart;
import
org.alfresco.service.cmr.repository.MimetypeService;
import
org.alfresco.service.cmr.repository.NodeRef;
import
org.alfresco.service.namespace.QName;
Now for some details,
first you will notice that processMessage no longer calls its super
class, leaving this class with the sole responsibility to handle the incoming
email to a folder.
public void processMessage(NodeRef folderNodeRef,
EmailMessage message){
String toAddress = message.getTo();
String fromAddress =
message.getFrom();
String subject =
message.getSubject();
|
In this part of the code you can see how you can get the
String for where the email was sent to “message.getTo()” who the email was sent from
“message.getFrom()” and the subject line “message.getSubject()”.
log.info("An Email was sent to:
" + toAddress);
log.info("An Email was sent
from: " + fromAddress);
log.info("An Email was sent with
the subject line of: " + subject);
|
This is just the log messages
for(EmailMessagePart attachment:
message.getAttachments()) {
//Skip saving the email as an
html file
if(!attachment.getFileName().startsWith(subject)){
|
An email can contain several attachments so this is here to
iterate through each one. The if
statement is for a special case.
Alfresco considers the body of the email to be a file, well it creates
an html version of it. It names it
after the subject line plus a few characters the .html. This may not be the best way to skip
uploading this object but it works well enough for a demonstration.
log.info("attached file
is named: " + attachment.getFileName()
+
"And Has a size of: " + attachment.getSize() + " Bytes");
|
Another log message that gives the object name and size in
bytes
contentIs =
attachment.getContent();
mimeType = mimetypeService.guessMimetype(attachment.getFileName());
contentNodeRef =
addContentNode(getNodeService(),
folderNodeRef, attachment.getFileName(), true);
writeContent(contentNodeRef,
contentIs, mimeType,
attachment.getEncoding());
|
contentIs =
attachment.getContent(); gets the java.io.InputStream of the attachment.
mimeType =
mimetypeService.guessMimetype(attachment.getFileName());
This guesses the mimetype based on the name. There is
another one that guesses the mimetype based on the name and does a quick search
on the file, but that is more processing time.
contentNodeRef
= addContentNode(getNodeService(),
folderNodeRef, attachment.getFileName(), true);
If my memory serves me right on this one, it create a stub
file to write to in the correct location.
folderNodeRef must be the parent director you want to place this file
into. The Boolean on the end, if set to
true, will overwrite any file with the same name, if you set it to false it
will change its name so it can still be uploaded.
If I remember right I remember this being an issue with
action folders. If a folder will perform
an action when a new file is created within it then this addContentNode will
cause that action to happen even though we have yet to write to it, just a word
of warning… that is if I remember correctly.
writeContent(contentNodeRef,
contentIs, mimeType,
attachment.getEncoding());
This writes the content out. :)
Now recompile the code, add the new jar file and restart
tomcat.
> javac
-d dist -cp
/opt/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-repository-4.0.e.jar:/opt/tomcat/webapps/alfresco/WEB-INF/lib/log4j-1.2.15.jar:/opt/tomcat/webapps/alfresco/WEB-INF/lib/alfresco-data-model-4.0.e.jar ./com/_10x13/alfresco/email/CustomFolderEmailMessageHandler.java
|
This will place the
.class file in the dist directory.
Now create the jar
file
> jar
cfv custom-email.jar -C dist/ .
|
copy the jar file to
tomcat
> sudo cp custom-email.jar
/opt/tomcat/webapps/alfresco/WEB-INF/lib/
|
restart tomcat
> sudo /etc/init.d/tomcat stop
> sudo /etc/init.d/tomcat start
|
Now send a new email in this time with attachments. In my case I attached two files
- Binding Bird.docx
- signed.png
And here you can see that the folder only contains those
attachments and no other fluff.
I hope this guide helps you out. It was a pain when I had to figure it out.
References
[1] Javadoc Alfresco
Folder email handler
Visited 10/2012
[2] Alfresco SMTP
Configuration
Visited 11/2012
Hey Patrick,
ReplyDeleteI've been referencing your blog a lot lately, and I thank you for your Alfresco posts!
I think I've discovered how to extend the inboundSMTP-context.xml without simply overwriting the original. It appears that due to changes around 3.2-3.3 (https://issues.alfresco.com/jira/browse/ALF-4361), the new path for overwriting the inbound and outbound SMTP is now extension/subsystems/email/InboundSMTP/inbound/inboundSMTP-context.xml.
Just wanted to pipe in and give my 2 cents!
Thanks,
Jon
Well written and very easy to follow.
ReplyDeleteThank you, you made my day.
Perfect HowTo. Thanks a lot. It saves me ages. Even works with Alfresco 5.1.
ReplyDeleteI have only a little issue.
My annomymous user catches no mails. ERROR: "The eMail user [mail hidden] does not referece a valid accessible node"
The user is in group EMAIL_CONTRIBUTORS but no admin user in alfresco.
I setted up a folder alias. But i do not recive any mail.
For all other users it work like a charm. Any help?