# AltaVista Mail API

Digital (TM) Equipment Corporation makes no representations that the use of its products in the manner described in this publication will not infringe on existing or future patent rights, nor do the descriptions contained in this publication imply the granting of licenses to make, use, or sell equipment or software in accordance with the descriptions.

Possession, use, or copying of the AltaVista Mail software described in this publication is authorized only pursuant to a valid written license from Digital or an authorized sublicensor.

Copyright © Digital Equipment Corporation 1996.

This document describes the application programming interface supported by the AltaVista Mail SMTP and POP3 server.

API version: | 1, 2
Software version: | 1.0, 2.0
Document revision number: | 2.0
Document revision date: | 16 September 1996

If you intend to use this document to help in integrating an application with AltaVista Mail, we strongly encourage you to contact the AltaVista Mail engineering support address, altavista-mail@digital.com, to discuss your requirements. We'll be happy to offer advice, example programs, and any updates to this reference information.

# Contents

1. Introduction
2. Client model
   1. Mailboxes, usernames and delivery
   2. Users, clients and client types
3. Client operations
   1. Installing and deinstalling the client
   2. Setting up the client's mailboxes
      1. Per-user or shared mailboxes
      2. Picking mailbox names
      3. Setting mailbox usernames
      4. Setting the Client Type attribute
      5. Creating the mailboxes
   3. Starting the client process
   4. Finding the client's mailboxes
   5. Fetching messages from a mailbox
   6. Processing the recipients of a fetched message
   7. Submitting messages to the SMTP server
4. Reference
   1. Parameters
   2. Errors
   3. Functions
      1. Avm_Init
      2. Avm_RegisterClientType
      3. Avm_DeregisterClientType
      4. Avm_StartClientType
      5. Avm_ScanMailboxes
      6. Avm_CreateThread
      7. Avm_ScanMessages
      8. Avm_GetMessage
      9. Avm_GetRecipient
      10. Avm_AcceptRecipient
      11. Avm_RejectRecipient
      12. Avm_RedirectRecipient
      13. Avm_ExpandRecipient
      14. Avm_RetryRecipient
      15. Avm_GetHeaderField
      16. Avm_GetContentLine
      17. Avm_PutMessage
      18. Avm_PutRecipient
      19. Avm_PutHeaderField
      20. Avm_PutContentLine
      21. Avm_EndMessage
      22. Avm_AbortMessage

# Introduction

The AltaVista Mail SMTP and POP3 server includes a simple application programming interface (API) intended for use by gateways and mail forwarding agents located on the same computer as the server.

The API exists because there is no standardized method for retrieving messages from an SMTP system that will preserve the recipient information required by a gateway. Retrieval would normally be performed using the POP3 protocol, but this protocol discards the actual recipients of a message, leaving only the To: and Cc: fields to which the message was (or may have been) originally directed, not the recipients the local system is actually responsible for. This means that POP3 can be used only for final delivery to a single user. (This hasn't stopped people from writing programs that try to distribute mail further, but such programs cannot work correctly in all cases and can cause message loss, repeated delivery and even indefinite routing loops.)

It is possible to build a gateway colocated with the AltaVista Mail server that does not use this API. We haven't published the file and message structures used by the server, but if you take a look at them you'll discover that they're text-based and extremely simple. You could very easily integrate your own program with the server with no further help.

However, the API offers some substantial benefits.

- The server's file formats are very likely to change. For example, any future extension of the server to support ESMTP is likely to cause ESMTP data to appear in the message files as well as the RFC 821 data used at present.

  Of course, the API will change as well, but we aim to preserve compatibility with the original semantics where possible.

- Gateways that use the API automatically get their message operations logged within the AltaVista Mail log system. This makes the gateway's routine operation visible to an interested administrator. Messages can be traced not only as far as the gateway but also into the foreign mail system: the log entries can include the foreign system's originator and recipeint names (so recording address translations) and the foreign system's message-identifier (so allowing the message to be traced further if the foreign system also logs its operations).

- Any problems with the operation of the API are fully reported in the AltaVista Mail Errors log. You don't have to deal with a potentially large range of errors from the SMTP system: an API call either works or it doesn't, and if it doesn't there's an accurate description of the problem in the Errors log.

- The API offers a very straightforward representation of SMTP message data. Return path and recipients are individually extracted. Header fields are individually handled using field type and value strings with multiline headers handled automatically. Message content lines are simple lines of text, with illegally long lines automatically split.

- Message recipient handling is extremely flexible. On delivery, each recipient can be individually accepted, rejected, redirected or expanded to a list of target addresses. You can even ask that a recipient be sent back for a retry if you can't process it immediately: you'll see the message again later but with only those recipients you've asked to have retried.

  These facilities aren't comprehensive - they don't necessarily mean you never have to generate your own non-delivery reports, for example - but they can greatly simplify your recipient and message queueing requirements.

- The API contains an optional facility to start the gateway process automatically during system startup: the gateway is installed as a Windows NT service under the same account as the AltaVista Mail server.

In general, none of the things the API does is difficult or clever; but if you use the API you'll find you've avoided having to write some extremely messy and error-prone code.

# Client model

## Mailboxes, usernames and delivery

When AltaVista Mail performs local delivery, it does so by leaving messages in a mailbox. This is a file system directory, and the delivered messages appear there as files, one message per file.

AltaVista Mail perform message delivery to a specific mailbox when the message's recipient address matches one of the usernames associated with that mailbox. A mailbox can have any number of associated usernames. Each username can be a simple string (say, 'User.Name'), or it can include a domain name component (say, 'User.Name@some.domain.name'). If present, the domain name must match the one in the recipient address for delivery to take place.

A username can include a single leading wildcard. This is an asterisk (*) character at the start of the name. It matches any string: a mailbox whose usernames include the value '*abc' will take delivery of any messages whose recipient addresses end with 'abc' before the domain name component (eg 'abc@host.name', 'xxxabc@host.name. and so on). A domain name can again be included (say, '*abc@domain.name'); again, the message recipient's domain name must match for delivery to take place.

Usernames without wildcards take precedence over usernames with wildcards, and more specific wildcards take precedence over less specific. Consider mailboxes A, B and C with usernames of '*', '*a' and 'cba' respectively. A message sent to 'xxx@host.name' will be delivered to mailbox A; one sent to 'aaa@host.name' will be delivered to B; and one sent to 'cba@host.name' will be delivered to C.

## Users, clients and client types

Each mailbox serves some number of users - the users whose usernames are associated with the mailbox. Any message delivered to the mailbox is on its way to one or more of those users. The message's next step is to be fetched out of the mailbox by some kind of client program.

To determine the behaviour appropriate to a mailbox, each mailbox has an associated client type. So, for example, a mailbox of type 'POP3' tells the server to offer access to the mailbox using the POP3 protocol; and a mailbox of type 'list' tells the server to forward messages delivered to the mailbox to the mailing list members associated with the mailbox.

When you write a gateway or other client program, you are defining a new client type. Installing or running your gateway will make the type known to the AltaVista Mail server, and mailboxes of your client type can be created, either by your own setup program or by an AltaVista Mail administrator. These mailboxes become your gateway's responsibility: you must fetch and process any messages delivered there. (The API includes a service to find all the mailboxes you must serve, so it's not difficult to do.)

The ability to serve multiple mailboxes may not seem necessary to your application, but it's very useful. In general, you should use a single mailbox to denote a single user community or a single distinct configuration. (A mailbox has its own directory and you can store configuration files there if you wish - don't give them a file extension of '.821' and the server won't think they're messages.)

For example, a cc:Mail gateway might use a single mailbox to denote a connection to a single cc:Mail post office. A single gateway can then support connections to multiple cc:Mail post offices by serving multiple mailboxes.

Another example might be a redirection server that uses a mailbox per organization served. Then if an organization is no longer to be served, it can be deleted as a unit without having to weed out individual redirection entries.

Many gateways have similar properties, but even if it isn't particularly useful to collect your gateway's user community into groups, you should at least serve all your mailboxes, treating them all in the same way: then if an administrator makes a configuration error and gives another mailbox your client type you don't stop serving the mailbox you did intend to serve.

# Client operations

As far as the API is concerned, the tasks performed by a gateway or other client program consist of:

- Installing and deinstalling the client

- Setting up the client's mailboxes

- Starting the client process

- Finding the client's mailboxes

- Fetching messages from a mailbox

- Processing the recipients of a fetched message

- Submitting messages to the SMTP server

## Installing and deinstalling the client

To install your client and have it automatically started on system startup, call Avm_RegisterClientType. This registers your client program as a Windows NT service running under AltaVista Mail's own Windows NT account, and makes its client type known to the server.

To deinstall your client, call Avm_DeregisterClientType. This deletes the Windows NT service and removes its client type from AltaVista Mail's list of known client types.

If the provided startup mechanism is inconvenient, for example because your client must run under a specific account, you don't have to call these services. If you don't, you are responsible for starting and stopping your client process, and must ensure that the account you do use has sufficient privilege to access the AltaVista Mail directories.

## Setting up the client's mailboxes

All local delivery is performed through mailboxes, so if your client will be responsible for accepting mail from the Internet, you'll have to set up one or more mailboxes to receive it. At the very least, you'll have to tell the AltaVista Mail administrator how to set them up.

### Per-user or shared mailboxes

If your client knows all its users individually, you can set up a mailbox for each user in advance of their being able to use the client. Mail for a user is then queued to the user's own mailbox, and you can retrieve it from there. Each user can choose their own username(s), and you can if necessary store per-user information in each mailbox. Any messages sent to multiple users will be processed by your client multiple times - every message you see will be bound for a single user, even if it appears to have multiple recipients.

If your client can't be expected to know all its users, for example because it's a gateway to a foreign mail system and you can't or don't want to resolve changes in the user base, you can set up a shared mailbox. This typically serves an entire user community. While you can still allow users to choose their own usernames (you just add all the usernames to the list associated with the mailbox), it's usually more convenient to have all your users share an address stub (a common trailing part of all email addresses), and register that stub as a wildcard username on the mailbox.

### Picking mailbox names

Mailboxes are named within an hierarchical structure that reflects the file system directories used to implement the mailbox storage. The top level of the structure is initially set up by AltaVista Mail itself.

You should pick a mailbox naming scheme sympathetic to that already present. If you serve individual end users, put their mailboxes under the 'Users' hierarchy; if you're building a gateway, put them under 'Gateways'; if a list server, under 'Mailing lists'. If you will routinely support multiple mailboxes, consider grouping yours under a common dummy mailbox (one with no usernames, so no delivery will be made there, and an Undefined client type).

### Setting mailbox usernames

The usernames you assign to your mailboxes completely determine which messages are delivered there. For a mailbox that serves one or more named end users, assign those users' usernames. For a mailbox serving an indefinite number of users, pick a wildcard username. For example, if you assign a username of '*%mygate' to a mailbox, all recipients whose email addresses end in '%mygate@local.host.name' will be delivered to the mailbox.

The percent (%) sign in the username above is quite a good delimiter character. Internet users are familiar with a percent sign being used to access gateways, as it's commonly used to invoke the source routing mechanism that operates many gateways.

### Setting the Client Type attribute

Your client is known to AltaVista Mail by its client type and description. You need to choose suitable values for these. A client type is typically one or two short words, and a description up to five or six words; combined, they must be recognisable from the Client Type drop-down box in the administration GUI. Use only alphanumeric characters in your client type string.

Examples of client types and descriptions are:

- List: manually maintained mailing list
- POP3: Post Office Protocol
- ccmail: AltaVista Mail gateway for cc:Mail

Assign this colon-separated form of the client type and description to the Client Type attribute of each of your mailboxes.

### Creating the mailboxes

To create your mailboxes, you can if necessary provide specific instructions to the AltaVista Mail administrator. This might be appropriate for per-user mailboxes - the task is similar to creating POP3 mailboxes.

If your gateway will typically serve only a small and fixed number of mailboxes, it'd be a much better solution if you could create the mailbox yourself from your setup code. To do this, use the AltaVista Mail administration protocol. This is easier than it sounds, and you can telnet to port 1655 to try it for yourself: here, for example, is the complete protocol exchange to create a mailbox. (Commands to the server are shown in italic type, responses in Roman.)

    +OK AltaVista Mail F1.0/1.0 BL17 Admin <41.833299608.168@local.host.name>
    login clear postmaster really-bad-password
    +OK Postmaster
    create mailbox my-gateway@Gateways
    +OK Mailbox created
    set mailbox my-gateway@Gateways
    +OK <Attribute>: <Value>?  '.' to finish
    ClientType: MyGate: My own gateway
    +OK <Attribute>: <Value>?  '.' to finish
    Usernames: *%mygate
    +OK <Attribute>: <Value>?  '.' to finish
    .
    +OK Done
    quit
    +OK Administration server signing off

Here, a mailbox called my-gateway has been created subordinate to the existing (dummy) Gateways mailbox. (Position within the hierarchy is not significant to AltaVista Mail - it's arranged at the administrator's convenience.) Its client type is 'MyGate', client description is 'My own gateway', and it receives mail for all addresses that end with '%mygate@local.host.name'.

The AltaVista Mail administration protocol is documented separately.

## Starting the client process

If you've used Avm_RegisterClientType to install your client program as a Windows NT service, the program will be run automatically on system startup. If you haven't, you must make your own arrangements to start the program.

In either case, you must make two calls to initialize the API.

First call Avm_Init. This tells the API which version of the API specification your calls will be following: any given set of API libraries may support multiple versions. To use the calls described in this specification, ask for version 1 or 2: version 1 if your application will need to work against an AltaVista Mail version 1.0 server, and version 2 if you require behaviour added in version 2.0 of the server. Except where otherwise noted, this document describes behaviour common to both versions. The major differences in the API versions are in the Avm_GetContentLine and Avm_PutContentLine functions.

Next, call Avm_StartClientType. This tells the API which client type your process is serving.

Call these routines as soon as you can after your process starts up. If you've used Avm_RegisterClientType to start up as an NT service, your call to Avm_StartClientType will contact the NT Service Control Manager to confirm that the process has been created successfully, and a long delay will make Windows NT believe there's something wrong. So if you have lengthy tasks to perform during process initialization, don't wait for them to complete before making these calls. If a later phase of initialization fails, you're free to let the process die.

## Finding the client's mailboxes

Your client is potentially responsible for fetching messages from multiple mailboxes. To find the mailboxes you serve, call Avm_ScanMailboxes until it says there are no more.

For most gateways, it's convenient to write a routine that serves a single mailbox, and then create a thread running that routine for each mailbox you find. To create a thread, call Avm_CreateThread.

You don't have to make your gateway a multithreaded program, and even if you do, you don't have to use Avm_CreateThread. It's provided as a convenience in case you wouldn't otherwise have been writing multithreaded code.

## Fetching messages from a mailbox

Fetching messages involves using two API functions. Call Avm_ScanMessages to get the filenames of the messages in the mailbox; and for each of these filenames, call Avm_GetMessage to start processing the message.

Scanning for message filenames is handled separately from opening the messages to give you some control over how and when you process specific messages. Suppose you have problems in handling a message, perhaps because some remote resource required by the message is unavailable. If you remember its filename, you can skip over it when you see it on subsequent scans, and try processing it again only when enough time has elapsed to make a retry worthwhile.

To fetch the various items of message data, use the following API calls in the order given:

- Avm_GetMessage has already been called. This returns the return path (the address to which any non-delivery reports should be sent), and the Received-ID (a server-assigned unique identifier for this instance of the message, used in logging message transfer).

- Avm_GetRecipient returns a single RFC 821 recipient. Call this routine until it returns no more recipients.

- Avm_GetHeaderField returns a single RFC 822 header field. Call this routine until it returns no more header fields. (In API version 2, you can instead use Avm_GetContentLine to retrieve header fields and their terminating blank line exactly as they appear in the message, omitting any calls to Avm_GetHeaderField.)

- Avm_GetContentLine returns a single line of non-header message content. (In API version 2, it can also retrieve header lines.) Call this routine until it returns no more content data. (Note that the API does not deal with MIME structures; you have to decode MIME messages yourself from the lines of content and the Content-type: header field.)

- Avm_EndMessage tells the API that you've finished processing the message. If your client is a gateway to a foreign mail system, pass in the foreign system's representation of the message's return path and message identifier (if the foreign system supports such structures). This information will then appear in the AltaVista Mail logs and will help in message tracing.

If during processing you find that you can't handle the message, call Avm_AbortMessage. This closes the message but leaves it in the mailbox, so future Avm_ScanMessages loops will see it again. Any stored log information and messages generated during recipient processing are discarded. If any of the above API functions fails (returns a negative value), Avm_AbortMessage has already been called: you need to call it yourself only for problems that you detect in your own code.

## Processing the recipients of a fetched message

Fetching a message means taking responsibility for the message's transfer, and hence taking responsibility for processing each of the message's recipients. In general, recipients must be handled independently of each other: processing some may succeed while others fail, and some failures will be temporary and others permanent. The AltaVista Mail API provides services to make it easy to handle these different outcomes.

Whenever you finish processing a recipient returned by Avm_GetRecipient, call one of the following functions:

- Avm_AcceptRecipient. This indicates that you have provisionally accepted responsibility for the recipient. (The acceptance is only provisional because if you later call Avm_AbortMessage the entire operation is aborted and you'll get to see the message and all its recipients again.) If your client is a gateway to a foreign mail system, this function is used to report the translated recipient address so it gets logged in the AltaVista Mail logs.

- Avm_RejectRecipient. This indicates that you have provisionally rejected the recipient. You should provide a rejection reason, and, if appropriate, the part of the recipient's address that caused the rejection.

- Avm_RedirectRecipient. This creates a copy of the message addressed to the recipient you provide. You can also provide a replacement for the message's return path (that is, a new target for any non-delivery reports the message subsequently generates). The new message will be released to the SMTP server when you call Avm_EndMessage for the message you're fetching (and will be deleted if you instead call Avm_AbortMessage).

  This function is of most use to clients whose major purpose is to redirect mail.

- Avm_ExpandRecipient. This creates a copy of the message addressed to a list of recipients. Make a call for each recipient in the list. The new message will be released to the SMTP server when you call Avm_EndMessage for the message you're fetching (and will be deleted if you instead call Avm_AbortMessage).

  This function is of most use to mailing list servers.

- Avm_RetryRecipient. This indicates that you can't currently process the recipient, and you want to see the message again later with only those recipients that were retried.

If you make your next call to Avm_GetRecipient without having made any of the above calls, you are assumed to have accepted the recipient. Note, though, that you won't have had the opportunity to report the translated recipient address, as you would if you'd called Avm_AcceptRecipient.

## Submitting messages to the SMTP server

Submitting messages to the SMTP server involves a sequence of calls similar to fetching and processing messages in a mailbox. For each message you want to submit, call the following functions in the order given:

- Avm_PutMessage starts creating a new message. Pass in the return path (the RFC 821 address where any non-delivery reports should be sent). The function returns the Received-ID (a server-assigned unique identifier for this instance of the message, used in logging message transfer) that will be used for the new message.

- Avm_PutRecipient adds an RFC 821 recipient address. If your client is a gateway to a foreign mail system, pass in the foreign form of the recipient address (its value before you translated it to an RFC 821 email address).

  Call this function once for every recipient.

- Avm_PutHeaderField adds an RFC 822 header field. You must be sure to add all the mandatory fields (Date:, an originator, and at least one recipient); the API won't try to observe this rule for you, and won't check that you've followed the rule either. It will split header fields longer than 80 characters into multiple lines.

  Call this function once for every header field. (In API version 2, you can instead use Avm_PutContentLine to add preformatted header fields and their terminating blank line exactly as you want them to appear in the message, omitting any calls to Avm_PutHeaderField.)

- Avm_PutContentLine adds a single line of non-header message content. (In API version 2, it can also add preformatted header lines.)

  Call this function once for every content line.

- Avm_EndMessage finishes creating the new message, releases it to the SMTP server for routing, and issues log entries into the AltaVista Mail logs. If your client is a gateway to a foreign mail system, you should pass in the foreign versions of the return path and message identifiers (if the foreign mail system supports such structures). This information will then appear in the AltaVista Mail logs and will help in message tracing.

If while submitting the message you encounter a problem, you can abort the submission by calling Avm_AbortMessage. This deletes the message you're constructing and discards any log information associated with it. If any of the above API functions fails (returns a negative value), Avm_AbortMessage has already been called: you need to call it yourself only for problems that you detect in your own code.

# Reference

## Parameters

Individual descriptions for parameters to the API functions are collected here. All string parameters are null-terminated.

- Version

  To provide an easy migration path as the mail system is developed, any given set of AltaVista Mail libraries may support multiple versions of the API specification. This specification describes version 1, so to get the behaviour described here, use the value 1.

- ClientType, ClientDescription

  A client type and client description are the names that distinguish your program from the other kinds of client that may be integrated with AltaVista Mail.

- Program

  The full file specification of your client's executable program.

- Directory

  The directory that serves as the message storage area for a mailbox. If you wish, you can store your own data in the directories your client serves. Don't use any filename that ends in '.821' or '.tmp', though, and don't use any filenames used by AltaVista Mail for its own operation. (All AltaVista Mail's data files have names that start with an underscore - '_' - so if you pick some other leading character you should be safe.)

- Address

  The Address parameter is the trailing part of the addresses served by a mailbox. That is, if Avm_ScanMailboxes returns an Address parameter with any given mailbox, any recipient address that ends with the value returned will be delivered to that mailbox.

  The Address parameter provides a convenient way for your client to construct Internet email addresses. Suppose a gateway to some foreign mail system serves a mailbox whose Address value is '%foreign@local.host.name'. For each user of the foreign mail system, it can append this value to the foreign recipient addresses - 'Fred.Bloggs' becomes 'Fred.Bloggs%foreign@local.host.name'. A message sent to this email address will normally be delivered to the gateway's mailbox.

  Note that the Address parameter simply gives access to any wildcard usernames associated with the mailbox. Since it's a wildcard, it can be overridden by a more specific wildcard or completely-specified username on another mailbox. This shouldn't be a problem under normal circumstances, but you should be aware that another client can claim part of your client's username space.

- Context

  A Context parameter is used by functions that scan lists of items. A scan function retrieves only one item per call, so multiple calls are needed to traverse an entire list. The Context parameter keeps track of the progress of the scan between calls.

  To start a scan, assign a NULL value to a pointer variable, and call the scan function to retrieve your first result, passing the address of your pointer variable as the Context parameter. For subsequent calls, don't change the Context parameter or the variable it points to.

  The scan function returns 1 for each item it retrieves. When there are no more it returns zero and assigns a NULL value to your Context variable. If you want to abort the scan, pass a NULL value for the scan function's output parameters: the scan will then skip the remaining values and return zero with a NULL Context variable as though you'd reached the end of the list.

- Main, Parameter

  The Main parameter provides the address of a main routine you want to call. The Parameter parameter provides a pointer to pass to that routine.

- Filename

  The filename of a message file in a mailbox.

- Message

  A Message parameter is an opaque handle on a message being fetched from a mailbox or built for submission to the SMTP server. All operations on messages are performed using API functions.

- ReturnPath, ForeignReturnPath

  A message's return path is the Internet email address to which any reports will be sent if the message is non-delivered. If empty, the message is itself a report.

  A foreign return path is a foreign mail system's representation of a return path. It's used by gateways, to record the correspondence between an Internet email address and the foreign address to or from which it was translated: since the translation may not be obvious, the foreign version must be logged to aid in message tracing.

- ReceivedId, ForeignId

  A ReceivedId is a unique identifier given to a specific instance of a message. It's the ID component of the message's first (most recent) Received: field. It is used within the AltaVista Mail logs to correlate all information about local operations on messages: using the Received-ID, you can work out exactly what's been done to any message in the local SMTP server.

  A Received: field is created (and its corresponding ID field assigned) when a message enters the SMTP server. Most operations on the message leave the field intact: so, for example, when a message's recipients are served by distinct targets, the message is split to each target, but each split retains the originally-assigned Received: field.

  A Received: field does change when the message replaces any of its recipients. When a recipient is redirected or expanded to a mailing list, a new Received: field is added to the new message to record the original recipient (and return path, if it's been replaced). When a message is non-delivered, the non-delivery report gets a complete new Received: list (it's actually a complete new message). In each case, an event is logged to keep track of the old and new Received-ID.

  A ForeignId is used by a gateway to a foreign mail system to express the foreign system's closest equivalent to a Received-ID: some kind of transaction identifier if possible, or a message ID if not. A transaction identifier is preferable because it's likely to keep track of individual instances of messages - a given message ID will typically appear in multiple messages (this is not an error, and there are good reasons why this will happen) so it isn't very good at working out the exact history of individual messages.

- Recipient, ForeignRecipient

  A Recipient parameter is a message recipient in RFC 821 format: user@host.name.

  A ForeignRecipient parameter is a foreign mail system's representation of a message recipient. It's used by gateways, to record the correspondence between an Internet email address and the foreign address to or from which it was translated: since the translation may not be obvious, the foreign version must be logged to aid in message tracing.

- Term, Reason

  A Reason parameter is a text string describing why a recipient is being non-delivered. A Term parameter is a text string containing the part of the recipient's address that's in error.

- FieldValueBufferSize

  The size you've allocated to hold a header field.

- FieldName, FieldValue

  An RFC 822 header field name and its value.

- Line

  A single line of non-header message content.

  The API handles the SMTP termination and transparency mechanisms. When writing content data, don't add a dot to lines that begin with a dot, and don't finish your input with a line containing a single dot; and when reading, don't remove any leading dot or treat a single dot as the end of content. The API does this for you.

## Errors

All the AltaVista Mail API functions indicate an error by returning a negative value. The precise cause of any error is logged in the Errors log, which you can monitor using the administration GUI or a Web browser (point it to http://client.host.name:1656/ ). The error cause is not made available to your calling code.

When a function that reads or writes message data encounters an error and returns a negative value, it has already called Avm_AbortMessage. There's no need for you to repeat this call (but it does no harm if you do). The functions that do this are Avm_GetMessage, Avm_GetRecipient, Avm_AcceptRecipient, Avm_RejectRecipient, Avm_RedirectRecipient, Avm_ExpandRecipient, Avm_RetryRecipient, Avm_GetHeaderField, Avm_GetContentLine, Avm_PutMessage, Avm_PutRecipient, Avm_PutHeaderField, Avm_PutContentLine, and Avm_EndMessage.

## Functions

### Avm_Init

Initialize the API.

    int Avm_Init                            /* 2=high, 1=OK, 0-low, -ve=error */
            (int Version);                  /* API version required */

For the semantics described by this version of the specification, pass a Version of 1 (if your application needs to work against an AltaVista Mail version 1.0 server) or 2.

### Avm_RegisterClientType

Make a client type known to the system. Call this function from your setup program. You'll need to run setup from an administrator's account.

    int Avm_RegisterClientType              /* -ve=error */
            (const char *ClientType,        /* Type identifier */
            const char *ClientDescription,  /* Descriptive name for type */
            const char *Program);           /* Program serving client type */

### Avm_DeregisterClientType

Remove the system's knowledge of a client type. Call this function from your deinstallation program. You'll need to do this from an administrator's account.

    int Avm_DeregisterClientType            /* -ve=error */
            (const char *ClientType,        /* Type identifier */
            const char *ClientDescription); /* Descriptive name for type */

### Avm_StartClientType

Initialize this process as the server for a client type. You can serve only one client type per process, and one process per client type.

    int Avm_StartClientType                 /* -ve=error */
            (const char *ClientType,        /* Client's type identifier */
            const char *ClientDescription); /* Descriptive name for type */

### Avm_ScanMailboxes

Find the mailboxes served by a specific client type.

    int Avm_ScanMailboxes                   /* 1=OK, 0=no more, -ve=error */
            (const char *ClientType,        /* Type identifier */
            const char *ClientDescription,  /* Descriptive name for type */
            char *Directory,                /* Mailbox directory */
            char *Address,                  /* Mailbox address stub */
            void **Context);                /* Context, initially &NULL */

### Avm_CreateThread

Spawn a detached thread.

    typedef int (*AvmThread) (void *Parameter);
    int Avm_CreateThread			/* -ve=error */
    	(AvmThread Main,		/* Thread's main routine */
    	void *Parameter);		/* Parameter to main routine */

This function calls the main routine you pass to it with the parameter you provide in a thread detached from the current thread of execution.

Note that such a detached thread runs completely independently, so it cannot share the values of any local variables with your calling code, or even parameters passed to the calling routine. If you wish to pass parameters to the new thread, allocate a block of virtual memory, copy the parameters into the block, and pass the address of the block to the thread. Get the thread to deallocate the memory when it's finished with the parameters. (If the call to Avm_CreateThread fails, you will have to deallocate the memory in the calling routine: the thread can't do so because it didn't get created.)

### Avm_ScanMessages

Find the messages delivered to a mailbox.

    int Avm_ScanMessages                    /* 1=OK, 0=no more, -ve=error */
            (const char *ClientType,        /* Client's type identifier */
            const char *ClientDescription,  /* Descriptive name for type */
            const char *Directory,          /* Mailbox directory */
            char *Filename,                 /* Message filename; NULL=abort */
            void **Context);                /* Context, initially &NULL */

### Avm_GetMessage

Open a message in a mailbox.

    int Avm_GetMessage                      /* 1=OK, 0=gone/locked, -ve=error */
            (const char *ClientType,        /* Client's type identifier */
            const char *ClientDescription,  /* Descriptive name for type */
            const char *Directory,          /* Mailbox directory */
            const char *Address,            /* Mailbox address stub */
            const char *Filename,           /* Message filename */
            AvmMessage *Message,            /* Handle on message */
            char *ReturnPath,               /* Originator, usually */
            char *ReceivedId);              /* Message Received-ID */

To find the message filenames to pass to Avm_GetMessage, use Avm_ScanMessages.

If Avm_GetMessage returns zero, the message is either no longer present in the mailbox, or it's currently locked by another process. This is not normally a serious problem, so you should not treat it as an error.

### Avm_GetRecipient

Get the next recipient of a message retrieved from a mailbox.

    int Avm_GetRecipient                    /* 1=OK, 0=no more, -ve=error */
            (AvmMessage *Message,           /* from _GetMessage */
            char *Recipient);               /* Next recipient */

Call Avm_GetRecipient immediately after your call to Avm_GetMessage, and continue calling it until it returns zero (or negative).

### Avm_AcceptRecipient

Report acceptance of a recipient.

    int Avm_AcceptRecipient                 /* -ve=error */
            (AvmMessage *Message,           /* from _GetMessage */
            const char *ForeignRecipient);  /* Recipient's foreign address */

Call Avm_AcceptRecipient immediately after the Avm_GetRecipient call that returned the recipient you want to accept. You do not have to call this function, but if you don't the translated address won't be logged.

### Avm_RejectRecipient

Request non-delivery of a recipient.

    int Avm_RejectRecipient                 /* -ve=error */
            (AvmMessage *Message,           /* from _GetMessage */
            const char *Term,               /* Offending address term */
            const char *Reason);            /* Rejection reason */

Call Avm_RejectRecipient immediately after the Avm_GetRecipient call that returned the recipient you want to reject.

### Avm_RedirectRecipient

Redirect a recipient to another email address.

    int Avm_RedirectRecipient               /* -ve=error */
            (AvmMessage *Message,           /* from _GetMessage */
            const char *ReturnPath,         /* New return path; NULL=no change */
            const char *Recipient);         /* New recipient */

Call Avm_RedirectRecipient immediately after the Avm_GetRecipient call that returned the recipient you want to redirect. You can provide a new return path to change the destination for non-delivery reports, but if the existing return path is null (ie this message is itself a report) it will be ignored.

### Avm_ExpandRecipient

Redirect a recipient to a list of email addresses.

    int Avm_ExpandRecipient                 /* -ve=error */
            (AvmMessage *Message,           /* from _GetMessage */
            const char *ReturnPath,         /* New return path; NULL=no change */
            const char *Recipient);         /* New recipient */

Call Avm_ExpandRecipient immediately after the Avm_GetRecipient call that returned the recipient you want to expand, once for each new recipient.

Do not call this routine unless you know you're expanding a list. If your system doesn't distinguish between redirection and list expansion, make this call only if you have more than one replacement recipient. If you don't, the logging will be wrong.

You can provide a new return path to change the destination for non-delivery reports, but if the existing return path is null (ie this message is itself a report) it will be ignored. Also, you must provide the new return path for a given recipient on the first call for that recipient; values given on subsequent calls will be ignored.

### Avm_RetryRecipient

Send a recipient back into the mailbox for retry at some later point.

    int Avm_RetryRecipient                  /* -ve=error */
            (AvmMessage *Message);          /* from _GetMessage */

Call Avm_RetryRecipient immediately after the Avm_GetRecipient call that returned the recipient you want to retry.

### Avm_GetHeaderField

Get the next RFC 822 header field.

    int Avm_GetHeaderField			/* 1=OK, 0=no more, -ve=error */
    	(AvmMessage *Message,		/* from _GetMessage */
    	int FieldValueBufferSize,	/* Size of field value buffer */
    	char *FieldName,		/* Field name */
    	char *FieldValue);		/* Field value */

Call this routine immediately after Avm_GetRecipient returns zero, and continue calling it until it returns zero (or negative). (In API version 2, you can instead use Avm_GetContentLine to retrieve header fields exactly as they appear in the message: just omit the calls to Avm_GetHeaderField.)

If the header field is split across multiple lines, Avm_GetHeaderField joins the lines back into a single value parameter. Extremely long header fields will be truncated; you can avoid this by passing a value buffer large enough to contain any reasonable field size.

If you're not interested in the actual message you've retrieved because you've rejected, redirected, expanded or retried all of the message recipients, you can skip this and subsequent stages and make your final call to Avm_EndMessage. The header and content data will be transcribed into the output messages without your having to read it.

### Avm_GetContentLine

Get the next line of content data.

    int Avm_GetContentLine                  /* 1=OK, 0=no more, -ve=error */
            (AvmMessage *Message,           /* from _GetMessage */
            char *Line);                    /* Line of data.  Allow 1K. */

Call Avm_GetContentLine after Avm_GetHeaderField returns zero, and continue calling it until it returns zero (or negative). (In API version 2, you can also use this function to retrieve header field data, including the header's terminating blank line: to do this, start your calls after Avm_GetRecipient returns zero.)

Content lines should normally limited to 80 characters, and it's illegal under SMTP to ship lines longer than 1000 characters. Although AltaVista Mail will accept and transfer illegally long lines, the Avm_GetContentLine function will truncate them. You should allow 1024 characters for a line buffer.

### Avm_PutMessage

Create a new message bound for the SMTP system.

    int Avm_PutMessage                      /* -ve=error */
            (const char *ClientType,        /* Client's type identifier */
            const char *ClientDescription,  /* Descriptive name for type */
            const char *Directory,          /* Mailbox directory */
            const char *Address,            /* Mailbox address stub */
            const char *ReturnPath,         /* Originator, usually */
            AvmMessage *Message,            /* Handle on new message */
            char *ReceivedId);              /* Received-ID that will be allocated */

The mailbox directory and address stub parameters are used only for logging purposes - messages are given to the SMTP server itself, not a mailbox.

### Avm_PutRecipient

Add a recipient to an SMTP message.

    int Avm_PutRecipient                    /* -ve=error */
            (AvmMessage *Message,           /* from _PutMessage */
            const char *Recipient,          /* Envelope recipient */
            const char *ForeignRecipient);  /* Recipient's foreign address */

Call Avm_PutRecipient immediately after Avm_PutMessage, once for each recipient.

### Avm_PutHeaderField

Add a header field to an SMTP message.

    int Avm_PutHeaderField                  /* -ve=error */
            (AvmMessage *Message,           /* from _PutMessage */
            const char *FieldName,          /* Field name */
            const char *FieldValue);        /* Field value (no CRLFs) */

Call Avm_PutHeaderField immediately after your last call to Avm_PutRecipient, once for each header field. (In API version 2, you can instead use Avm_PutContentLine to add preformatted header fields: just omit any calls to Avm_PutHeaderField.) Long header fields will automatically be split onto multiple lines. (You may not like where this happens, so avoid this if you can. For example, when adding a Content-type: field for a multipart MIME message, use the shortest suitable Boundary value you can generate.)

### Avm_PutContentLine

Add a content line to an SMTP message.

    int Avm_PutContentLine                  /* -ve=error */
            (AvmMessage *Message,           /* from _PutMessage */
            const char *Line);              /* Content line (no CRLFs) */

Call Avm_PutContentLine after the last call to Avm_PutHeaderField, once for each line of content data. Aim to limit your lines to 80 characters. If you don't, Avm_PutContentLine will split the line at a place of its choosing. (In API version 2, you can use this function to add preformatted header field data, including the header's terminating blank line: to do this, start calling Avm_PutContentLine immediately after your last call to Avm_PutRecipient.)

### Avm_EndMessage

Finish processing a message.

    int Avm_EndMessage                      /* -ve=error */
            (AvmMessage *Message,           /* from _GetMessage/_PutMessage */
            const char *ForeignReturnPath,  /* Return path's foreign address */
            const char *ForeignId);         /* Foreign message-ID */

When processing a fetched message, call Avm_EndMessage after your last call to Avm_GetContentLine (or your last recipient-processing function if you weren't actually looking at the data) to delete the message from the mailbox and release any derived messages and log information.

When creating a new message, call Avm_EndMessage after your last call to Avm_PutContentLine to release it and any derived log information to the SMTP server.

### Avm_AbortMessage

Give up processing a message.

    int Avm_AbortMessage                    /* -ve=error */
            (AvmMessage *Message);          /* from _GetMessage/_PutMessage */

When processing a fetched message, call Avm_AbortMessage to give up, returning the message to the mailbox and discarding any derived messages and log information.

When creating a new message, call Avm_AbortMessage to give up, discarding the message structures and log information created so far.