Index: openacs-4/packages/acs-mail/www/doc/openacs-mail.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-mail/www/doc/openacs-mail.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-mail/www/doc/openacs-mail.html 13 Aug 2001 18:24:35 -0000 1.1 @@ -0,0 +1,482 @@ + + + + OpenACS-mail + + + +

OpenACS-mail

+ by Vinod Kurup (vkurup@massmed.org) +
+

Purpose

+
+

+ This document explains the structure and function of the acs-mail + package in OpenACS 4. +

+ +

+ acs-mail is a package that provides basic mail services to other + OpenACS packages. +

+
+ +

A Little History

+
+

+ Within aD's version of ACS 4.x, there were three packages that + handled outgoing email messaging - acs-messaging, acs-mail and + acs-notifications. acs-messaging was built using the content + repository to allow the bboard package to send out email. acs-mail + came later with a little more mail functionality, including the + ability to send out multipart email messages. acs-notification was + a package that maintained a complex mail queue (the other two + packages implemented much simpler queues that place most of the + burden on the MTA). It also implemented a mail package inside + Oracle that sent the outgoing mail. Both acs-mail and acs-messaging + use ns_sendmail to send out mail, making them db-independent. +

+ +

+ Our first goal was to simplify this by removing the notifications + package and replacing that functionality (basically one function) + inside acs-mail. Another goal was to have acs-mail use the content + repository so that it can take advantage of all the CR functions. +

+ +

+ We haven't merged acs-messaging and acs-mail, although I think that + we should do this at some point. Currently, they provide very + similar functionality. +

+
+ +

Package overview

+
+

+ There are a few basic tables that the user needs to know about. The + acs_mail_bodies table contains the attributes of the mail + message. The most important column in this table is the + content_item_id attribute. This is a space for a cr_item from the + Content Repository. Note that this column is a foreign key to + acs_objects, rather than to cr_items as one would expect. This is + because the API uses this column to decide whether or not the + message is a simple message or a multipart message. If the column + contains a value which is present in acs_mail_multiparts, then the + message is a multipart message. If not, then it is a simple + message. Thus the column can't be a foreign key to cr_items since + in the case of multipart messages, it won't contain a cr_item's + item_id. Also, note that you should not use header_from and + header_to columns in this table. Instead, you'll create the mail + body as a generic mail body and then give it a from: and to: value + when you queue it. So why are they there? Good question. It may be + that they are there for incoming messages. But since that is not + implemented, I'm not sure. +

+ +

+ The table acs_mail_body_headers allows you to add arbitrary + headers to your message. The column body_id in this table is a + foreign key to acs_mail_bodies +

+ +

+ The table acs_mail_links contains 2 columns - a mail_link_id + and a body_id. After you create a acs_mail_body, you'll create a + mail_link and then insert the mail_link into the queue. Why the + abstraction? This was initially meant to be a point where garbage + collection could occur. So, other applications are supposed to + subclass acs_mail_links to their own use. They create a message + body and a mail_link. Once they're done, they delete the + mail_link. A scheduled process then looks for any message_bodies + that are not linked to mail_links any more. It deletes these + messages. This is not implemented yet (but would be rather easy to + do). +

+ +

+ Think of acs_mail_bodies as 'message bodies' and acs_mail_links as + 'messages'. An application can send the same email to multiple + people by creating one message body but associating that message + body with multiple messages. +

+ +

+ The table acs_mail_queue_messages is a table that contains + mail_links. The table acs_mail_queue_outgoing is the + outgoing queue and is a foreign key to acs_mail_queue_messages. It + also contains 2 other columns, envelope_from and envelope_to. This + is where you address the email. The table + acs_mail_queue_incoming looks just like the outgoing + queue. The plan is for the MTA to create mail bodies when incoming + messages arrive. It should then insert that mail_body into the + incoming queue. Other applications should then periodically scan + the incoming queue and grab messages that it wants (presumably + matching a pattern of some sort) and then deletes the message from + the incoming queue. +

+ +

+ The table acs_mail_multiparts contains the information about + multipart messages. The column multipart_kind is either + 'alternative' or 'mixed' (are there others?). The table + acs_mail_multipart_parts then contains the individual parts. +

+ +

+ The tcl procedure acs_mail_process_queue runs every 15 + minutes and sends out any messages in the outgoing queue. +

+ +

+ The acs-notifications package is built on top of acs-mail and hides + the complexity from the user (if you're satisfied with creating + plain-text messages). It's described next. +

+ +
+ +

How to send a notification

+
+

+ The simplest feature of the acs-mail package is the ability to send + a notification. A notification is a plain text email that is sent + from one party to another. With ACS 4.x, this was done using the + acs-notifications package as follows: +

+
+		nt.post_request (
+		  party_from   => :party_from,
+		  party_to     => :party_to,
+		  expand_group => 'f',
+		  subject      => 'my subject',
+		  message      => 'plain text message',
+		  max_retries  => 3
+		);
+	  
+

+ party_from and party_to are party_id's from the parties table. If + expand_group is true and party_to is a group_id, then the procedure + will send the email to each of the group's members. If expand_group + is false, then the email will only be sent to the group email + address. +

+

+ The openacs version is very similar. The max_retries parameter is + not used because, as mentioned above, acs-mail's queue is very + simple and relies on the MTA. So max_retries must be zero. Here's + the openacs version: +

+
+		select acs_mail_nt__post_request (
+		  :party_from,     -- p_party_from
+		  :party_to,       -- p_party_to
+		  'f',             -- p_expand_group
+		  :subject,        -- p_subject
+		  :message,        -- p_message
+		  0                -- p_max_retries
+		);
+	  
+

+ We've also overloaded the function so that you can call the + function with only the 4 essential parameters: party_from, + party_to, subject, and message. +

+ +

+ Note that acs-notifications is now completely gone. So event the + oracle queries have to be converted from nt.post_request to + acs_mail_nt.post_request. acs_mail_nt.cancel_requet is also + supported. All the other nt functions are deprecated and their + replacements (if any) are described in the file + packages/acs-mail/sql/oracle/acs-mail-nt-create.sql (or the + corresponding file in the postgresql directory) +

+ +
+ +

Creating a HTML message

+
+

+ Creating a simple email message consists of the following steps: +

+
    +
  1. Create a CR item with your message
  2. +
  3. Create a new acs_mail_body with content_item=(item_id of your CR item)
  4. +
  5. Queue the message
  6. +
+ +

From PL/SQL

+
+
+begin
+    -- usually the content_item will already be created by your app
+    -- for it''s own purposes
+    v_item_id := content_item__new ( ... );
+    v_revision_id := content_revision__new ( ... v_item_id ... );
+    perform content_revision__set_live_revision( v_revision_id );
+
+    v_subject := ''My subject'';
+    v_user_id := 2222;
+    v_ip_addr := ''10.0.0.1'';
+
+    -- create an acs_mail_body
+    v_body_id := acs_mail_body__new (
+        null,              -- p_body_id
+        null,              -- body_reply_to
+        null,              -- body_from
+        now(),             -- body_date
+        null,              -- header_message_id
+        null,              -- p_header_reply_to
+        v_subject,         -- p_header_subject
+        null,              -- p_header_from
+        null,              -- p_header_to
+        v_item_id,         -- p_content_item_id
+        ''acs_mail_body'', -- p_object_type
+        now(),             -- p_creation_date
+        v_user_id,         -- p_creation_user
+        v_ip_addr,         -- p_creation_ip
+        null               -- p_context_id
+    );
+
+    -- put the message on the queue 
+    v_mail_link_id := acs_mail_queue_message__new (
+        null,             -- p_mail_link_id
+	    v_body_id,        -- p_body_id
+        null,             -- p_context_id
+        now(),            -- p_creation_date
+        v_user_id,        -- p_creation_user
+        v_ip_addr,        -- p_creation_ip
+        ''acs_mail_link'' -- p_object_type
+    );
+
+    v_from_addr := ''sender@openacs.org'';
+    v_to_addr   := ''recipient@openacs.org'';
+
+    -- put the message on the outgoing queue
+    insert into acs_mail_queue_outgoing
+    ( message_id, envelope_from, envelope_to )
+    values
+    ( v_mail_link_id, v_from_addr, v_to_addr )"
+
+    return 0;
+end;
+		
+
+ +

From tcl

+
+

+ The tcl procedure acs_mail_body_new allows you to create + messages from text content (-content), binary files + (-content_file) or a CR item (-content_item_id). +

+
+set header_subject "My subject"
+set content "My message is here."
+set content_type "text/plain"
+		  
+# create a mail body
+set body_id [acs_mail_body_new -header_subject $header_subject \
+    -content $content -content_type $content_type]
+
+# queue it
+set sql_string "select acs_mail_queue_message.new (
+                  null,             -- p_mail_link_id
+                  :body_id,         -- p_body_id
+                  null,             -- p_context_id
+                  now(),            -- p_creation_date
+                  :user_id,         -- p_creation_user
+                  :ip_addr,         -- p_creation_ip
+                  'acs_mail_link'   -- p_object_type
+                );"
+
+set mail_link_id [db_string queue_message $sql_string]
+
+# put in in outgoing queue
+set sql_string "
+insert into acs_mail_queue_outgoing
+ ( message_id, envelope_from, envelope_to )
+values
+ ( :mail_link_id, :from_addr, :to_addr )"
+
+db_dml outgoing_queue $sql_string
+		  
+		
+
+ +
+ +

Creating a multipart/alternative message

+
+

+ The steps here are: +

+ + +

Example in tcl

+
+
+
+# create the multipart message ('multipart/mixed')
+set multipart_id [acs_mail_multipart_new -multipart_kind "mixed"]
+
+# create an acs_mail_body (with content_item_id = multipart_id )
+set body_id [acs_mail_body_new -header_subject "My subject" \
+		-content_item_id $multipart_id ]
+
+# create a new text/plain item
+set content_item_id [db_string create_text_item "
+    select content_item__new (
+        'acs-mail message $body_id-1', -- name
+        ...
+        'text message',                -- title
+        ...
+        'text/plain',                  -- mime_type
+        ...
+        'plain message content'        -- text
+        ...
+    )
+"]
+
+acs_mail_multipart_add_content -multipart_id $multipart_id \
+		-content_item_id $content_item_id
+
+# create a new text/html item
+
+set content_item_id [db_string create_html_item "
+    select content_item__new (
+        'acs-mail message $body_id-2', -- name
+        ...
+        'html message',                -- title
+        ...
+        'text/html',                   -- mime_type
+        ...
+        'HTML message content', -- text
+        ...
+
+    )
+"]
+
+acs_mail_multipart_add_content -multipart_id $multipart_id \
+		-content_item_id $content_item_id
+
+# create a new binary item
+# from file that was uploaded
+
+set mime_type "image/jpeg"
+
+set content_item_id [db_string create_jpeg_item "
+    select content_item__new (
+        'acs-mail message $body_id-3', -- name
+        ...
+        :mime_type,                    -- mime_type
+        ...
+    )
+"]
+
+set revision_id [db_string create_jpeg_revision "
+    select content_revision__new ( ... )
+"]
+
+db_transaction {
+	db_dml content_add "
+        update cr_revisions
+        set content = empty_blob()
+        where revision_id = :revision_id
+        returning content into :1
+" -blob_files [list ${content_file.tmpfile}]
+}
+
+
+db_1row make_live {
+	select content_item__set_live_revision(:revision_id);
+}
+
+# get the sequence number, so we can make this part an attachment
+set sequence_num [acs_mail_multipart_add_content -multipart_id $multipart_id \
+		-content_item_id $content_item_id]
+
+db_dml update_multiparts "
+    update acs_mail_multipart_parts 
+      set mime_disposition='attachment; filename=\"myfile.jpg\"' 
+      where sequence_number=:sequence_num and 
+            multipart_id=:multipart_id"
+
+set sql_string "select acs_mail_queue_message.new (
+                  null,             -- p_mail_link_id
+                  :body_id,         -- p_body_id
+                  null,             -- p_context_id
+                  now(),            -- p_creation_date
+                  :user_id,         -- p_creation_user
+                  :ip_addr,         -- p_creation_ip
+                  'acs_mail_link'   -- p_object_type
+                );"
+
+set mail_link_id [db_string queue_message $sql_string]
+
+set sql_string "
+    insert into acs_mail_queue_outgoing
+     ( message_id, envelope_from, envelope_to )
+    values
+     ( :mail_link_id, :from_addr, :to_addr )"
+
+db_dml outgoing_queue $sql_string
+
+		
+
+
+ +

Some other notes

+
+ +
+
+
Vinod Kurup
+ + +Last modified: Fri Aug 10 21:46:41 EDT 2001 + + +