Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mailing List Records #93

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

swflint
Copy link
Contributor

@swflint swflint commented Jun 7, 2020

I've started working on the mailing-list record type. I'm going to leave this here, and as a draft, but I'd appreciate your comments (and help)!

* ebdb.el: (ebdb-field-list-type) Define a type specific to
mailing-lists to describe what kind of mailing list a mailing-list
record is.

* ebdb.el: (ebdb-record-mailing-list) Begin updating mailing-list
record type definition.
@swflint
Copy link
Contributor Author

swflint commented Jun 7, 2020

Related to #92

@girzel
Copy link
Owner

girzel commented Jun 7, 2020

Thanks for working on this!

I guess my first instinct was to use further record subclasses to represent different types of mailing list. So ebdb-record-mailing-list would be a parent class, and there would be subclasses for mailman, google, etc, as necessary. In general, in EBDB, I've tried to use classes and subclasses to answer the question "what is it", and fields just to hold instance-level data. Using a list-type field class seems to confuse this separation of concerns: if we want to know exactly how a mailing-list instance should behave, we would need to first look at its class, then look at what sort of list-type field it had.

Practically, this shakes out in the definition of generic functions. If all "identity" information is held in the class, generic functions are written as:

(cl-defgeneric ebdb-mailing-list-do-something ((rec ebdb-mailing-list-mailman))
  (do-something-mailman))

Whereas if we use a "list-type" slot+field, it's:

(cl-defgeneric ebdb-mailing-list-do-something ((rec ebdb-mailing-list))
  (let ((list-type (slot-value rec 'list-type)))
    (cl-case (slot-value list-type 'list-type)
      ("mailman" (do-something-mailman))
      ("google" (do-something google)))))

The former ends up being more code (and it actually runs slower, not that I think that's a big deal), but has the advantage that third-party developers could write an add-on (someday they will! I can dream!) defining a new mailing-list type, without having to touch EBDB at all. In the latter situation, we'd have to let them "get inside" the generic function, which would probably mean a lookup in an alist defvar, the way Elisp usually does it. I've tried to avoid that sort of thing in EBDB.

But it would be interesting to see how far we can get without needing to know about the exact type of mailing list. Specifically, well-formed lists all send the same set of headers: List-ID, List-Archive, List-Help, etc. I think the first thing to do is think about how to store this information (a single field type with separate slots for each header type? separate slots on the record itself?) in a way that will make it easy for the user to, eg, open the archive URL for a mailing list.

In the end we may find that we don't actually need to specify whether the mailing list is Google, mailman, etc.

Thanks again!

@swflint
Copy link
Contributor Author

swflint commented Jun 7, 2020

Part of the reason I used the type field is that it makes it easy to edit/change (I've had lists switch hosting on me, sadly), though I imagine it wouldn't be bad either way. I also thought of using something like an ebdb-mailing-list-action-alist where action is some mailing list action, and it's organized with types as keys. The use of generics, however, is probably better, as it would let us store, for instance, mailing list type specific information (to do certain actions with listserv, iirc, you need to send a password).

@girzel
Copy link
Owner

girzel commented Jun 7, 2020

Huh, I hadn't thought of mailing lists changing providers. But I still think there's hope to get by without specifying type at all, until we really confirm that there are lists out there that don't conform to the standard headers.

I guess I'm leaning toward one slot to hold the List-ID, another slot with a field type that holds all the URLs and mail addresses for control (help, unsubscribe, subscribe, post, etc), and has a list of "actions" that let you pick which you're using, and maybe a slot holding an instance of ebdb-field-obfuscated, for the password? Dunno, just spitballing. What else would we want?

@swflint
Copy link
Contributor Author

swflint commented Jun 7, 2020

That's probably a better option then. I'd still think that maybe a way of handling modifying reply-to would be useful. Keeping List-ID and similar would be helpful. But each type can generally have its control addresses deduced pretty easily, and I'd rather generate that as needed than have to store all of them.

ListServ in particular is a funny one, and part of the reason for the line of subtypes or keeping types thought (you have one address, and you send commands to that, often in a batch). Not to mention its weird attachments feature. As a note, those passwords tend to be short and sent back in plain text on a semi-regular basis.

@girzel
Copy link
Owner

girzel commented Jun 8, 2020

I agree that generating as much as possible is a good idea.

Maybe we need a bit of taxonomy to see exactly how different the various list servers are from one another?

@swflint
Copy link
Contributor Author

swflint commented Jun 8, 2020

Agreed.

@swflint
Copy link
Contributor Author

swflint commented Jun 10, 2020

So, here's what I'm thinking (and whether or not we auto-detect or something else), we use the object-based system, and we split into two main types, address-based control and command-based control. Because, for the most part, auto-detection of addresses is possible, I don't think further specialization is necessary. Command-based control may require it, but even then, I'm not sure.

Also: how can I make the records displayable? Because I don't want them to be entity-types (as there's no need for all that goes along with that), I can't get them to display.

@girzel
Copy link
Owner

girzel commented Jun 11, 2020 via email

@swflint
Copy link
Contributor Author

swflint commented Jun 11, 2020 via email

@girzel
Copy link
Owner

girzel commented Jun 11, 2020 via email

@girzel
Copy link
Owner

girzel commented Jul 15, 2020

You're doing a prototype of this, not me -- right? :)

@swflint
Copy link
Contributor Author

swflint commented Jul 15, 2020 via email

@swflint
Copy link
Contributor Author

swflint commented Jul 15, 2020

Btw, would you be interested in moving each type of record (other than the most basic), to its own file? I think it would make extension easier, as well as make maintenance long-term easier.

@girzel
Copy link
Owner

girzel commented Jul 15, 2020

Huh, I hadn't thought of that. I guess I'd be almost more likely to move the fields out into their own file... Maybe both records and fields? It can get a little tricky because class definitions need come before all references, which has resulted in some odd code positioning already.

ebdb.el is getting a little large... I guess this is a good idea, but not a priority?

@ghost
Copy link

ghost commented Sep 23, 2022

Hi, just chiming in to ask if there are any updates on this. I'm currently saving mailing lists as person records but it'd be great having first-class support for them.

@girzel
Copy link
Owner

girzel commented Dec 5, 2022

Hi, just chiming in to ask if there are any updates on this. I'm currently saving mailing lists as person records but it'd be great having first-class support for them.

Hey! Sorry for the very slow reply. I'm still really interested in getting this done, but it's been hard just getting past the requirements stage.

It seems like, however the actual mailing list records end up working, one of the most important aspects of behavior will be automatic creation: the user shouldn't have to manually select a record type. So I think I'll start working on it from that end, instead.

It looks to me like the "List-Id" header is the most reliable way of detecting a mailing list (I mean there's "Precedence: list", but "List-Id" has the actual information we want). So I will alter ebdb-message-headers to add another header class, which will either be called 'list or 'public.

One problem is that things like newsletters often have a (garbage) "List-Id" header, but obviously no "List-Post". So some part of the system will have to grow some tests: if both "List-Id" and "List-Post" are present, make a mailing list. Otherwise, do nothing (though I suppose we could add a newsletter type record, if for no other purpose than to make unsubscribing easier).

I suppose I can implement this much without having to set in stone everything about the mailing list record class – it's not too disruptive to add new slots to an existing class. I think starting off with a "post-address" mail field, an "unsubscribe-address" mail field, a "receipt-address" mail field (for the user's own email), and an "archive-url" URL field should do it.

I guess ebdb-update-records will be the best place to provide different behavior based on the kind of email this is: personal correspondence, mailing list post, newsletter, one-time security code, Slack notification, etc. Personally I don't use automatic record creation simply because there's a minority of emails I receive that are actually from a person I want to add to EBDB. But we could make it smarter about skipping some types of emails. Something interesting could be done about mails where the "From" and "Return-Path" addresses don't match, for instance...

Anyway, I'm thinking out loud. Let me see how far I can get, and please chime in with comments/requests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants