Well, here it is, in all it glorious unoptimised “beauty” 
I apologise in advance if looking at this drives (or makes) you mad.
I haven’t even tried to consider optimisation, so if you see improvements, please let me know.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
-- This is primarily for the HMS translation and UTC offset – using do shell script with date will obviate the need for this framework, I believe
use framework "Foundation"
-- Define size of inline attachments above which we keep the imported attachments and delete the MIME part
set minPictureSize to 50000 -- put in scope to round up to next divisible by 4 numnber if changed
-- Figure out the base64-encoded size of minPictureSize – we'll add line breaks later (technically, line lengths won't always be 76)
set minbase64size to (round (minPictureSize / 3) rounding up) * 4
-- Let's set up our MIME part delimiting stuff
set partDelimiter to "\n--"
set currentRecordNum to 0
--with timeout of 600 seconds
-- select the Mail mailfolder the source messages are in
-- Grab the list of mailboxes
tell application "Mail"
set {mailAccountIDs, mailAccountNames, mailAccountsMailboxes} to accounts's {id, name, mailboxes}
set localMailboxes to its mailboxes
end tell
-- Create lists of them
set mailboxList to {}
set chooseMailboxList to {}
repeat with currentAccountNum from 1 to (count mailAccountIDs)
set suffix to " of account " & mailAccountNames's item currentAccountNum
repeat with currentMailAccountsMailbox in my mailAccountsMailboxes's item currentAccountNum
set my mailboxList's end to {(currentMailAccountsMailbox as record)'s «class seld» & suffix, (currentMailAccountsMailbox as record)'s «class seld», mailAccountIDs's item currentAccountNum}
set my chooseMailboxList's end to (currentMailAccountsMailbox as record)'s «class seld» & suffix
end repeat
end repeat
repeat with localMailbox in my localMailboxes
set my mailboxList's end to (localMailbox as record)'s «class seld»
end repeat
set selectedMailbox to choose from list chooseMailboxList with prompt "Select mail folder:" default items (first item of chooseMailboxList)
repeat with currentMailboxDetails in mailboxList
if currentMailboxDetails contains selectedMailbox then
set SelectedMailboxName to item 2 of currentMailboxDetails
set SelectedMailboxAccountID to item 3 of currentMailboxDetails
end if
end repeat
-- display dialog SelectedMailboxName & " – " & SelectedMailboxAccountID
-- /select the Mail mailfolder the source messages are in
set countAdj to 0 -- not sure I'm using this. I think it was meant to exclude non-e-mail records in the chosen group
-- Where are we saving the .mbox file? This could be a dialog selection
--set mboxFolder to "~/Desktop"
-- What are we naming the .mbox file?
-- get last component of mailbox path (mailbox name) and use it in the import .mbox file's name
set AppleScript's text item delimiters to "/"
set mboxFileName to (last text item of SelectedMailboxName as string) & " Import.mbox"
set AppleScript's text item delimiters to ""
-- Full path to .mbox file?
--set mboxFilePath to mboxFolder & "/" & mboxFileName
-- Let's get the file reference
--set mboxFile to mboxFilePath as string
set mboxFile to (((path to desktop folder) as string) & mboxFileName)
--remove existing .mbox import file, if any
try
tell application "Finder" to delete file mboxFile
end try
tell application "DEVONthink"
activate
-- Let's set the group for messages
set emailsGroup to display group selector "Select a group with e-mails:" buttons {"Cancel", "OK"}
-- Let's set the group for attachments
set attachmentsGroup to display group selector "Select a group for attachments:" buttons {"Cancel", "OK"}
-- Set up some variables for the progress indicator
set countRecords to (count children of emailsGroup)
set startTime to current date
set elapsedTimeHMS to ""
-- Let's go!
try
-- Where are we up to?
show progress indicator "Separating attachments…" steps (countRecords + countAdj)
-- Go through the group with the e-mails
repeat with currentItem in (children of emailsGroup)
repeat 1 times -- can I get rid of this?
--Which record are we at?
set currentRecordNum to currentRecordNum + 1
-- Some more progress indicator stuff once we've passsed one record processed
if currentRecordNum > 1 then
set elapsedTime to round ((current date) - startTime)
set perItemTime to round (elapsedTime / (currentRecordNum - 1))
set totalEstTime to elapsedTime + perItemTime * (countRecords - currentRecordNum)
set elapsedTimeHMS to my secondsToHMS(elapsedTime)
--set elapsedTimeHMS to secondsToHMS from elapsedTime
set totalEstTimeHMS to my secondsToHMS(totalEstTime)
set timeProgressString to " (" & elapsedTimeHMS & "/" & totalEstTimeHMS & ")"
else -- or for first record
set timeProgressString to ""
end if
-- And show the calculated progress numberds and current record name
step progress indicator (currentRecordNum as string) & "/" & (countRecords as string) & timeProgressString & ": " & name of currentItem
-- Only process records with attachments
if attachment count of currentItem > 0 then
-- We need the UUID because it's basically the Message-ID we'll search for later (we'll strip the < and > then)
set recordUUID to the uuid of currentItem
-- set recordID to the id of currentItem
-- new message, nothing deleted yet
set attachmentsDeleted to false
-- We need the DEVONthink item link because we'll put that into the URL field of the imported attachments we're keeping in DEVONthink
set recordRefURL to the reference URL of currentItem
-- Now we import the attachments and hold onto a reference to them all
set importedAttachments to import attachments of record currentItem to attachmentsGroup
-- Looping through those attachments, we'll delete pictures smaller than 50,000 bytes, and set the URL to the e-mail for everything else
repeat with currentAttachment in importedAttachments
if (the record type of currentAttachment) as string = "picture" and (the size of currentAttachment) < minPictureSize then
delete record currentAttachment
else
set the URL of currentAttachment to recordRefURL
-- we also give the tag for this item on whether to do anything with the source data )any time we keep an attachment in DEVONthink we wantt o delete it from the mail source and save that modified source in the mbox file
set attachmentsDeleted to true
end if
end repeat
-- Once attachments processed, if any were kept, let's work on the e-mail for inclusion in the .mbox file
if attachmentsDeleted then
tell application "Mail"
-- activate
-- Which mail folder are we to look for the message in?
set mailFolder to mailbox SelectedMailboxName of account id SelectedMailboxAccountID
-- Let's prepare the Message-ID and find any matching message/s in the appropriate folder
set matchingMessageID to (rich text 2 thru -2 of recordUUID)
set matchingMessages to (messages whose message id is matchingMessageID) of mailFolder
-- OK, we'll repeat the following for each found message for now
-- ** I can probably just use the first matching message (as second messages won't be imported into DEVONthink anyway
-- ** That would mean the line above would change, and we can remove the loop folloiwng immediately here
repeat with currentMessage in (get matchingMessages)
-- Clear the .mbox placeholder variable for a new message
set messageMboxText to ""
-- Create the first line of the message in .mbox
set msgFrom to extract address from (sender of currentMessage)
set dateMsgReceived to the date received of currentMessage
set mboxMsgStart to my mboxFirstLine(msgFrom, dateMsgReceived)
set messageMboxText to messageMboxText & mboxMsgStart
-- Grab the source of the message
set messageSource to (the source of currentMessage)
-- ** Do I need this again?
set messageID to the message id of currentMessage
-- ** Grab the headers - I wonder if I can just test the whole message and if that will be quicker than grabbing headers and then testing?
set messageHeaders to all headers of currentMessage
-- We test to see if the message has multiple MIME parts - we ignore otherwise
-- If we are only running this script against e-mails in DEVONthink which are showing attachments, this test is likely superfluous
if messageHeaders contains "Content-Type: multipart/" then
-- We do this so we can split the message by MIME parts (each text item is a MIME part)
set AppleScript's text item delimiters to partDelimiter
set messageParts to every text item of messageSource
set countMessageParts to count of messageParts
-- Grab everything up to the actual first MIME part
set messagePreamble to item 1 of messageParts
-- Grab the last MIME part (which will be a boundary ending spec)
set messagePostamble to item countMessageParts of messageParts
-- Start the .mbox data with the Preamble
set messageMboxText to messageMboxText & messagePreamble & partDelimiter
-- Loop through everything except the first and last parts
repeat with partNumber from 2 to (countMessageParts - 1)
-- Now we inspect and act on each part as necessary
set currentPart to item partNumber of messageParts
-- Attachments will always have the encoded part after two newlines, so now we split the currentPart using two newlines
-- ** This may be able to be swapped around with the Content-Type tests following
set AppleScript's text item delimiters to "\n\n"
-- Is there more than one section to this MIME part separated by two newlines?
-- Let's do something if there is
if (count text items of currentPart) > 1 then
-- Let's test for the inline Content-Types we want to consider actions for
-- if ((text item 1 of currentPart contains "Content-Type: image/") or (text item 1 of currentPart contains "Content-Type: application/")) ¬
-- and (text item 1 of currentPart contains "Content-Disposition: inline") then
-- Firstly inline images
if ((text item 1 of currentPart contains "Content-Type: image/")) and (text item 1 of currentPart contains "Content-Disposition: inline") then
-- grab the base64 data
-- This is for when inline or image parts don't have a second interpretable part 2025-07-28
try
set encodedData to text item 2 of currentPart
-- Check the line length of the base64 encoded data
set b64LineLength to count characters of (first paragraph of encodedData)
-- Add the base minimum base64 encoded size to the appropriate number of newline characters
set minMIMEEncodedSize to minbase64size + (round (minbase64size / b64LineLength))
-- Grab the size of the attachment's encoded data
set currentPartSize to count characters of encodedData
-- Is the encoded data smaller than our minimum size?
if currentPartSize < minMIMEEncodedSize then
-- If so, write that small encoded data into our .mbox variable
set messageMboxText to messageMboxText & currentPart & partDelimiter
end if
on error
set messageMboxText to messageMboxText & currentPart & partDelimiter
end try
-- For non-inline images, or application/ Content-Types
else if ((text item 1 of currentPart contains "Content-Type: image/") or (text item 1 of currentPart contains "Content-Type: application/")) then
-- Do nothing - i.e. don't add them to the .mbox variable
-- And for anything that doesn't have two newlines while also not matching the above Content-Type and size tests and exclusions
-- just write the part to .mbox variable (usually text/plain and text/html, for example)
else
set messageMboxText to messageMboxText & currentPart & partDelimiter
end if
-- And for "single" item MIME parts (i.e. no double newlines), just write the part to .mbox variable
else
set messageMboxText to messageMboxText & currentPart & partDelimiter
end if
-- Finish loop of message parts
set AppleScript's text item delimiters to ""
end repeat
-- We've inspected all the parts and taken appropriate action
-- let's write the last MIME part (last boundary closure)
set messageMboxText to messageMboxText & messagePostamble
-- Finish with multipart Mail message
end if
-- End loop of matching Mail records by UUID
end repeat
-- Exit Mail tell loop
end tell
-- ** Set up write to .mbox file here
try
set openMboxFile to open for access file mboxFile with write permission
write (messageMboxText & "\n\n") to openMboxFile starting at eof
close access openMboxFile
on error
try
close access openMboxFile
end try
end try
-- Finish with messages where attachments have been deleted
end if
end if
end repeat
-- End loop of DEVONthink selected items
end repeat
hide progress indicator
--end try
on error error_message number error_number
hide progress indicator
if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
end try
-- Exit DEVONthink tell loop
end tell
--end timeout
beep
beep
beep
beep
-- And we're done!
on mboxFirstLine(fromAddress, dateReceived)
set tz to current application's NSTimeZone's localTimeZone()
set theOffset to (tz's secondsFromGMTForDate:dateReceived)
set dateReceivedGMT to dateReceived - theOffset
set dateReceivedWeekday to characters 1 thru 3 of ((the weekday of dateReceivedGMT) as string) as string
set dateReceivedMonth to characters 1 thru 3 of ((the month of dateReceivedGMT) as string) as string
set dateReceivedTime to characters -1 thru -8 of (dateReceivedGMT as string) as string
set dateReceivedYear to year of dateReceivedGMT
set dateReceivedDay to characters -1 thru -2 of ("0" & (day of dateReceivedGMT)) as string
set mboxStartLine to "From " & fromAddress & " " & dateReceivedWeekday & " " & dateReceivedMonth & " " & dateReceivedDay & " " & dateReceivedTime & " " & dateReceivedYear & "\n"
return mboxStartLine
end mboxFirstLine
on secondsToHMS(theSecs)
set h to theSecs div 3600
set s to theSecs - h * 3600
set m to s div 60
set s to s - m * 60
set HMSSTring to (characters -2 thru -1 of (h + 100 as string) & ":" & characters -2 thru -1 of (m + 100 as string) & ":" & characters -2 thru -1 of (s + 100 as string)) as string
return HMSSTring
end secondsToHMS
on firstRun()
end firstRun
It’s happily processed the last few mailboxes without error, but it’ll be interesting to see how others get on.
It’s currently non-destructive – the e-mails are left in original state in DEVONthink and in Mail.
You can just delete the attachments group/s and the .mbox file/s generated and everything will be back to where it was when you started.
Once it’s more tidied up, I will delete the e-mail in DEVONthink after the .mbox is updated.
I’ll likely leave the unaltered e-mail in Mail (it still has read/replied/forwarded/redirected status which I am not importing) – I’ll likely archive it from there some other way.
Let me know what you think!
Sean