SpamSieve 3.1.3
SpamSieve 3.1.3 improves the filtering accuracy of my Mac e-mail spam filter. It works with the new MailMaven e-mail client and includes enhancements for notification and server junk filters, along with various other fixes and improvements.
Some interesting issues were:
The Mail extension API is only supposed to send the extension messages to filter “when it downloads a message,” but some customers were seeing it try to filter draft messages that were created locally on the Mac. Why would the user ever want those to be touched (FB17547044)?
One customer also reported that Mail sometimes doesn’t send the extension the correct message data. The headers are modified and reordered so that if SpamSieve sees the same message again later it thinks it’s a different message. There’s an experimental workaround for this, but it’s not clear why it’s only happening for this one user. There were several similar bugs in previous versions of Mail (where it would simply omit some of the message data when communicating with the extension), but those were much more widespread and easy to reproduce.
A longstanding problem, which we’ve worked around, is that sometimes Mail stops sending new messages to the extension to be filtered. I think there are multiple causes for this, but one that’s 100% reproducible is that it never works if the app owning the extension is launched after Mail itself (FB17368083).
SpamSieve uses SQLite.swift to read Mail’s database, and in rare cases it was crashing when the database wasn’t as expected. This is because there are several places where SQLite.swift is type-safe at compile time but not at runtime. It’s not safe to subscript a
Row
from the database, because if the column isn’t present or is unexpectedlyNULL
it will force unwrap and crash. There’s a correspondingget() throws
API that looks like it will be better because it reports errors, but to my surprise that also has some internal force unwraps. I had thought that by telling it that a column was aURL?
it would give me anil
if the string was not a valid URL. But, actually, it doesURL(string: stringValue)!
(and similarly forDate
andUUID
). I think the only safe thing to do is to read types that SQLite can natively query and convert them at the application level.In some cases, Core Data was spending a lot of time repeatedly reading the store’s options dictionary, and this was bridged from Swift so it got bogged down in
swift_dynamicCast()
. This all goes away if I give it a realNSDictionary
.This version includes the previously mentioned local network privacy fix.
Previously: