Index: src/test/java/org/apache/james/mime4j/MultipartTokensTest.java
===================================================================
--- src/test/java/org/apache/james/mime4j/MultipartTokensTest.java	(revision 669421)
+++ src/test/java/org/apache/james/mime4j/MultipartTokensTest.java	(working copy)
@@ -157,6 +157,28 @@
         checkState(MimeTokenStream.T_END_OF_STREAM);
     }
 
+    public void testMultipartMessageWithoutHeader() throws Exception {
+        parser.parseHeadless(new ByteArrayInputStream(US_ASCII.encode(BODY).array()), 
+                "multipart/mixed;boundary=1729");
+        checkState(MimeTokenStream.T_START_MULTIPART);
+        checkState(MimeTokenStream.T_PREAMBLE);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_EPILOGUE);
+        checkState(MimeTokenStream.T_END_MULTIPART);
+        checkState(MimeTokenStream.T_END_MESSAGE);
+        checkState(MimeTokenStream.T_END_OF_STREAM);
+    }
+    
     private void checkState(final int state) throws IOException, MimeException {
         assertEquals(MimeTokenStream.stateToString(state), MimeTokenStream.stateToString(parser.next()));
     }
Index: src/main/java/org/apache/james/mime4j/MimeTokenStream.java
===================================================================
--- src/main/java/org/apache/james/mime4j/MimeTokenStream.java	(revision 669421)
+++ src/main/java/org/apache/james/mime4j/MimeTokenStream.java	(working copy)
@@ -341,16 +341,27 @@
         private int pos, start;
         private int lineNumber, startLineNumber;
         private final int endState;
+        private boolean skipHead;
         
         String field, fieldName, fieldValue;
 
         Entity(Cursor cursor, BodyDescriptor parent, int startState, int endState) {
             this.parent = parent;
             this.cursor = cursor;
-            state = startState;
+            this.state = startState;
             this.endState = endState;
+            this.skipHead = false;
         }
 
+        void initEntityBody(String contentType) {
+            if (body != null) {
+                throw new IllegalStateException("Body already exists");
+            }
+            body = newBodyDescriptor(parent);
+            body.addField("Content-Type", contentType);
+            skipHead = true;
+        }
+        
         private void setParsingFieldState() {
             state = parseField() ? T_FIELD : T_END_HEADER;
         }
@@ -381,6 +392,12 @@
         int next() throws IOException, MimeException {
             switch (state) {
                 case T_START_MESSAGE:
+                    if (skipHead) {
+                        state = T_START_MULTIPART;
+                    } else {
+                        state = T_START_HEADER;
+                    }
+                    break;
                 case T_START_BODYPART:
                     state = T_START_HEADER;
                     break;
@@ -568,6 +585,7 @@
     }
     
     /** Instructs the {@code MimeTokenStream} to parse the given streams contents.
+     * <p/>
      * If the {@code MimeTokenStream} has already been in use, resets the streams
      * internal state.
      */
@@ -577,6 +595,21 @@
         state = parseMessage(cursor, null);
     }
 
+    /** Instructs the {@code MimeTokenStream} to parse the given content with 
+     * the content type. The message stream is assumed to have no message header
+     * and is expected to begin with a message body. This can be the case when 
+     * the message content is transmitted using a different transport protocol 
+     * such as HTTP.
+     * <p/>
+     * If the {@code MimeTokenStream} has already been in use, resets the streams
+     * internal state.
+     */
+    public void parseHeadless(InputStream stream, String contentType) {
+        entities.clear();
+        cursor = new StreamCursor(stream);
+        state = parseHeadlessMessage(cursor, contentType);
+    }
+
     private int parseMessage(Cursor cursor, BodyDescriptor parent) {
         switch (recursionMode) {
             case M_RAW:
@@ -592,6 +625,22 @@
         return currentStateMachine.state;
     }
     
+    private int parseHeadlessMessage(Cursor cursor, String contentType) {
+        switch (recursionMode) {
+            case M_RAW:
+                currentStateMachine = new RawEntity(cursor.nextSection());
+                break;
+            case M_NO_RECURSE:
+                // expected to be called only at start of paring
+            case M_RECURSE:
+                Message message = new Message(cursor, null);
+                message.initEntityBody(contentType);
+                currentStateMachine = message;
+                break;
+        }
+        entities.add(currentStateMachine);
+        return currentStateMachine.state;
+    }
     /**
      * Determines if this parser is currently in raw mode.
      * 
