private AttachedFileValue createAttachedFileValue(Date sentDate, BodyPart part)
        throws MessagingException, IOException {
      // Create attachment
      ValueBuilder<AttachedFileValue> attachmentBuilder =
          module.valueBuilderFactory().newValueBuilder(AttachedFileValue.class);

      AttachedFileValue prototype = attachmentBuilder.prototype();
      // check contentType and fetch just the first part if necessary
      String contentType = "";
      if (part.getContentType().indexOf(';') == -1) contentType = part.getContentType();
      else contentType = part.getContentType().substring(0, part.getContentType().indexOf(';'));

      prototype.mimeType().set(contentType);
      prototype.modificationDate().set(sentDate);
      String fileName = part.getFileName();
      prototype.name().set(fileName == null ? "Nofilename" : MimeUtility.decodeText(fileName));
      prototype.size().set((long) part.getSize());

      InputStream inputStream = part.getInputStream();
      String id = attachmentStore.storeAttachment(Inputs.byteBuffer(inputStream, 4096));
      String uri = "store:" + id;
      prototype.uri().set(uri);
      return attachmentBuilder.newInstance();
    }
      public void receivedEmail(ApplicationEvent event, EmailValue email) {
        UnitOfWork uow =
            module
                .unitOfWorkFactory()
                .newUnitOfWork(UsecaseBuilder.newUsecase("Receive email in conversation"));

        try {
          String references = email.headers().get().get("References");

          if (hasStreamflowReference(references)) {
            // This is a response - handle it!

            List<String> refs =
                (List<String>)
                    Iterables.addAll(
                        (Collection<String>) new ArrayList<String>(),
                        Iterables.iterable(references.split("[ \r\n\t]")));

            // Hotmail handles refs a bit differently...
            String hotmailRefs =
                Iterables.first(
                    Iterables.filter(
                        new Specification<String>() {
                          public boolean satisfiedBy(String item) {
                            return item.contains(",") && item.endsWith("@Streamflow>");
                          }
                        },
                        refs));

            String lastRef = null;
            if (!Strings.empty(hotmailRefs)) {
              lastRef = hotmailRefs.split(",")[1];
            } else {
              Collections.reverse(refs);
              Iterable<String> filter =
                  Iterables.filter(
                      new Specification<String>() {
                        public boolean satisfiedBy(String item) {
                          return item.endsWith("@Streamflow>");
                        }
                      },
                      refs);
              lastRef = Iterables.first(filter);
            }

            if (lastRef == null) {
              ValueBuilder<EmailValue> builder =
                  module
                      .valueBuilderFactory()
                      .newValueBuilder(EmailValue.class)
                      .withPrototype(email);
              String subj = "Msg Ref missing: " + builder.prototype().subject().get();
              builder.prototype().subject().set(subj.length() > 50 ? subj.substring(0, 50) : subj);

              systemDefaults.createCaseOnEmailFailure(builder.newInstance());
              logger.error("Could not find message reference in email header:" + lastRef);
              uow.discard();
              return;
            }

            Matcher matcher = Pattern.compile("<([^/]*)/([^@]*)@[^>]*>").matcher(lastRef);

            if (matcher.find()) {
              String conversationId = matcher.group(1);
              String participantId = URLDecoder.decode(matcher.group(2), "UTF-8");

              if (!"".equals(conversationId) && !"".equals(participantId)) {
                ConversationParticipant from =
                    uow.get(ConversationParticipant.class, participantId);
                Conversation conversation = uow.get(Conversation.class, conversationId);

                CaseEntity caze = (CaseEntity) conversation.conversationOwner().get();
                String content = email.content().get();

                // If we have an assignee, ensure it is a member of the conversation first
                if (caze.isAssigned()) {
                  if (!conversation.isParticipant(
                      (ConversationParticipant) caze.assignedTo().get()))
                    conversation.addParticipant((ConversationParticipant) caze.assignedTo().get());
                }

                // Create a new role map and fill it with relevant objects
                if (RoleMap.current() == null) RoleMap.newCurrentRoleMap();
                RoleMap.current().set(from, ConversationParticipant.class);
                RoleMap.current().set(caze, CaseLoggable.Data.class);
                RoleMap.current().set(caze, Case.class);

                Message message = null;

                if (Translator.HTML.equalsIgnoreCase(email.contentType().get())) {
                  message =
                      conversation.createMessage(email.contentHtml().get(), MessageType.HTML, from);
                } else {
                  message =
                      conversation.createMessage(email.content().get(), MessageType.PLAIN, from);
                }
                // Create attachments
                for (AttachedFileValue attachedFileValue : email.attachments().get()) {
                  if (!(attachedFileValue.mimeType().get().contains("text/x-vcard")
                      || attachedFileValue.mimeType().get().contains("text/directory"))) {
                    Attachment attachment = message.createAttachment(attachedFileValue.uri().get());
                    attachment.changeDescription("New Attachment");
                    attachment.changeName(attachedFileValue.name().get());
                    attachment.changeMimeType(attachedFileValue.mimeType().get());
                    attachment.changeModificationDate(attachedFileValue.modificationDate().get());
                    attachment.changeSize(attachedFileValue.size().get());
                    attachment.changeUri(attachedFileValue.uri().get());
                  }
                }

                try {
                  if (caze.isStatus(CaseStates.CLOSED)) {
                    RoleMap.newCurrentRoleMap();
                    RoleMap.current().set(caze);
                    if (caze.assignedTo().get() != null) {
                      RoleMap.current().set(caze.assignedTo().get());
                    } else {
                      RoleMap.current()
                          .set(uow.get(UserEntity.class, UserEntity.ADMINISTRATOR_USERNAME));
                    }
                    CaseCommandsContext caseCommands =
                        module.transientBuilderFactory().newTransient(CaseCommandsContext.class);
                    caseCommands.reopen();
                    caseCommands.unassign();
                    RoleMap.clearCurrentRoleMap();
                  }
                } catch (Throwable e) {
                  ValueBuilder<EmailValue> builder =
                      module
                          .valueBuilderFactory()
                          .newValueBuilder(EmailValue.class)
                          .withPrototype(email);
                  String subj = "Create Case failed: " + builder.prototype().subject().get();
                  builder
                      .prototype()
                      .subject()
                      .set(subj.length() > 50 ? subj.substring(0, 50) : subj);

                  systemDefaults.createCaseOnEmailFailure(builder.newInstance());
                  // throw new IllegalStateException("Could not open case through new message.", e);
                }
              }
            }
          }

          uow.complete();
        } catch (Exception ex) {
          ValueBuilder<EmailValue> builder =
              module.valueBuilderFactory().newValueBuilder(EmailValue.class).withPrototype(email);
          String subj = "Conversation Response Error: " + builder.prototype().subject().get();
          builder.prototype().subject().set(subj.length() > 50 ? subj.substring(0, 50) : subj);

          StringBuilder content = new StringBuilder();
          content.append("Error Message: " + ex.getMessage());
          content.append("\n\rStackTrace:\n\r");
          for (StackTraceElement trace : Arrays.asList(ex.getStackTrace())) {
            content.append(trace.toString() + "\n\r");
          }

          builder.prototype().content().set(content.toString());
          // since we create the content of the message our self it's ok to set content type always
          // to text/plain
          builder.prototype().contentType().set("text/plain");

          // Make sure to address has some value before vi create a case!!
          if (builder.prototype().to().get() == null) {
            builder.prototype().to().set("n/a");
          }

          systemDefaults.createCaseOnEmailFailure(builder.newInstance());
          uow.discard();
          // throw new ApplicationEventReplayException(event, ex);
        }
      }