Google Code offered in: English - Español - 日本語 - 한국어 - Português - Pусский - 中文(简体) - 中文(繁體)
Last updated April 13, 2011 (see recent changes)
The Google Apps Email Migration API allows administrators and users of Google Apps to migrate mail from legacy email systems into their domain's hosted Gmail accounts. Your client application can upload email messages into these accounts using standard Google Data API feeds.
Note: This API is available to Google Apps for free, Business, Education, and ISPs accounts, and cannot be used for migration into consumer Gmail accounts.
This document is intended for programmers who want to write client applications to allow domain administrators or end users to migrate email into Google Apps mailboxes. It provides some background on the capabilities of the Email Migration API. It also provides examples of basic data API interactions using raw XML and HTTP, as well as by using the client libraries.
This document assumes that you understand the general ideas behind the Google Data APIs.
For Apps Email Migration API reference information, see the reference guide.
You may want to create a Google Apps account for testing purposes. Email Migration uses Google Apps accounts, so if you already have a test account, you're all set. You can create new accounts from the Google Apps control panel or using the Provisioning API.
Fully functional samples demonstrating the Email Migration API in action are available in the client libraries. Pick a flavor you're most comfortable using. Follow the instructions below to test them out:
README. To run the sample you'll need to modify the following values in gdata/java/build.properties:
sample.appsforyourdomain.migration.username is the username you use to log in.sample.appsforyourdomain.migration.password is the password you use to log in.sample.appsforyourdomain.migration.domain is your domain name.Note: To migrate email to be owned by a different user, you must be an administrator; you can set the owner with the --destination_user command-line option.
To run the examples in this document you'll need to use the following import statements:
import com.google.gdata.client.appsforyourdomain.migration.*; import com.google.gdata.data.appsforyourdomain.migration.*; import com.google.gdata.util.*;
For more information, see Getting Started with the Java Client Library.
python migration_example.py -d <domain> -e <email> -p <password> -u <username> -f <filename>
Use the username argument to indicate the account to which mails are being migrated. The domain admin as well as the end user can both use this API, the difference being that the admins can use it to move messages for all accounts while end users can use it only on their own behalf.
The filename argument is the path of a .txt file that contains an RFC 822-encoded plain text message. To import several such files together, place all of them in a directory and pass the directory path to this argument. A typical usage of this sample would thus look like:
python migration_example.py -d 'example.com' -e 'admin@example.com' -p 'p@$$w0rd' -u 'john.smith' -f '/home/administrator/archives/jsmith/messages'
The sample uses the ImportMail, AddMailEntry, and ImportMultipleMails methods of the MigrationService class. Use the following import statement to work with them directly in your code:
from gdata.apps.migration import service
For more information, see Getting Started with the Google Data Python Library.
After compiling the sample, run it as follows:
migrationsample <domain> <userEmail> <password> [destinationEmail]
where domain is your Google Apps domain name, and userEmail and password are your administrator login credentials. Optionally, you may specify another email address on the domain, destinationEmail, into which the sample application will migrate mail messages. For example, if you're the owner of example.com, and you want to try migrating mail into test@example.com, invoke the sample as follows:
migrationsample example.com admin@example.com your_password test@example.com
The sample performs a number of operations to demonstrate the process of migrating mail into a hosted Gmail account. For more details, see the RunSample method of the code.
To compile the examples in this document into your own code, you'll need to use the following using statements:
using Google.GData.Apps.Migration; using Google.GData.Client; using Google.GData.Extensions.Apps;
The MailItemService class represents a connection to the feed that allows you to migrate mail messages into a hosted Gmail account.
For more information, see Getting Started with the .NET Client Library.
Limits and quotas protect the Google infrastructure from an automated process that uses the Email Migration API in an inappropriate way. Excessive requests from an API might result from a harmless typo, or may result from an inefficiently designed system that makes needless API calls. Regardless of the cause, blocking traffic from a specific source once it reaches a certain level is necessary for the overall health of the Google Apps system. It ensures that one developer's actions cannot negatively impact the larger community.
In the unlikely event that your API request fails, you'll receive an HTTP status code response. A status code of 403 has error information about incorrect input and an HTTP status code of 503 has error information indicating which API quotas have been exceeded. These responses allow your custom application to detect these errors and take appropriate action.
If your requests need to be completed in a fixed period of time, send your requests in parallel or use multiple threads in your Java or C# application. An example of parallel requests is requesting small batches of emails from different users rather than adding or removing lots of emails from one user simultaneously. In the case of threads, try starting with 10 threads, one thread per user email. Note, the thread recommendation has trade-offs and is not useful for all API situations. If the number of requests gets too high, quota errors will occur. Another trade-off example is the Email Migration API's quota for the maximum overall message upload rate. The upload rate is one API request - per second - per user, no matter how many threads are making upload requests.
For all errors that are time based (maximum of N things for N seconds per thread), especially the 503 status code errors, we recommend your code catch the exception and, using an exponential backoff algorithm, wait for a small delay before retrying the failed call. An Email Migration API example for one thread is to wait 5 seconds and retry the failed call. If the request is successful, repeat this pattern for the other threads. If the second request is not successful, your application should scale back on the frequency of the request until a call is successful. For example, increase the initial 5 second delay to 10 seconds and retry your failed call again. Also, decide on a retry limit. For example retry a request 5 to 7 times with different delay times before your application returns an error to the user.
| API Limit Categories | Limits |
|---|---|
| Message upload rate | The API has a rate limit per user. An upload rate to use as a reference is one request to the API - per second - per user. This limit could change depending on the system's capacity. |
| API Quota Categories | Quotas |
| Attachments, file formats | As a security measure to prevent potential viruses, the system does not allow executable files (.exe) even if they are sent in a zipped format (.zip, .tar, .tgs, .taz, .z, .gz) |
| Attachments, maximum number | The maximum number of attachments is unlimited. But if the sum of the email message's size and the attachment sizes, including the attachments' email transport encodings, can not exceed the 25MB email message quota. When using email, the sending or receiving of the this email message will fail and the message will be sent back to the sender. |
| ClientLogin authentication tokens | Valid for 24 hours. The error is '401 token expired' |
| Email address, size | The message header's From:, To:, Cc:, and Bcc: fields accept a valid email address up to 400 characters. |
| Email Inbox, disk space | The inbox default disk space is 25 GB for Premier Edition accounts, and 7+ GB for Standard and Education Editions.
When using email and in the case of troubleshooting storage errors with inbound messages, check your email forwarding setting. If you are geting quota errors and your account has not exceeded your email storage quota, you may be automatically forwarding your mail to another account that has exceeded its storage limits. One control panel tip is to delete your trash. If you have recently moved messages to the Trash, but have not seen a decrease in your disk space, confirm you have deleted the messages from your Trash label. |
| Email message, size | The maximum size for an email message is 25MB. This includes messages to individual users or to groups. This quota includes attachments which can increase in size when the email transport encodings are automatically added to the message. When using email, any message exceeding this quota limit is returned to the sender. |
| Inbox disk space | The inbox default disk space is 25 GB for Google Apps and Google Apps for Business, and 7.3 GB for Google Apps for Education. |
| Labels (used with folders) | Labels have a 255 character limit per label. During migration, a folder's full path becomes the label name. Nested folders are migrated as flat labels. Labels are not nested. |
| Message request, maximum | The maximum data for each HTTP POST request is 32MB. |
| Message text | The RFC 822 message should be UTF-8 text. Make sure each message has at least the From:, To:, and Date: header fields required by the RFC 822 specification. If a message is rejected as malformed, the system returns a 400 Bad Request HTTP status code. The Base 64 encoded RFC 822 message capability is now deprecated. |
| Other Types of Limits | Limitations and Guidelines |
|---|---|
| Client libraries | For the Java client library, use Java 1.5 or later. For a .NET client, use the .NET 1.1 runtime or later, and you should be current with all patches. |
| Email migration, by admin | Administrators, by default, have the API enabled. Administrators control whether users are allowed to migrate email using the Email Migration API. Only domain administrators can migrate to accounts other than their own. |
| Email migration, by user | Users need the API enabled by the administrator in the control panel using the 'Advanced tools' page's toggle in the 'User email uploads' section or by using the Admin Settings API. When an end user is migrating mail, the username in the feed's URL must be the same as the currently authenticated username. |
| Email migration options | Email migration from Lotus Notes, Microsoft Outlook, Microsoft Exchange options. |
| Email routing | If you are using the IMAP email migration and email routing services, use the Admin Settings API to let administrators specify the domain-level email routing to another email server. This is similar to the control panel's email routing settings. This can also be used with a dual delivery configuration to allow users continuous mail flow while their email is being migrated. |
| Groups, direct group membership or groups added to other groups (nested groups) | Outside of the Email Migration API and when using groups, a user's maximum number of direct group membership is 2000 groups.
If the user belongs to groups that have been added to other groups (nested groups), the sum of the direct and nested group membership must be equal to or less than 5000 groups. |
| Outbound email routing | The Admin Settings API configures outbound routing of email from users in your domain. |
| Passwords | Can contain any combination of characters. A minimum of 8 characters is recommended with a minimum of 6 characters required. |
| Usernames | Usernames can contain letters (a-z), numbers (0-9), dashers (-), underscores (_), and apostrophes ('). Google Apps recognizes dots or periods (.). This is not the same as Gmail. |
To migrate email messages, you must first authenticate your client. It can authenticate using either of two approaches: ClientLogin username/password or username/access code authentication, or OAuth for web applications.
If your client is a standalone single-user "installed" client (such as a desktop application), then you should use the ClientLogin Interface system; if your client is a multi-user web application client, then you should use 3-legged OAuth. Both of these methods involve interacting with an authentication service. The authentication service returns an authentication token that your client can then send to the Email Migration API service along with every subsequent request on behalf of that user.
For more information about authentication with Google Data APIs in general, see the authentication documentation.
The samples in this document assume you are providing the appropriate authentication.
Note: If you're using a client library, authentication will be managed for you by the library itself. You may skip directly to the section below to know how to do this.
Email Migration API supports 3-legged OAuth scheme for allowing web applications to migrate messages. The OAuth guide provides information on how to obtain access tokens. For more information, refer to the complete documentation on using OAuth with the Google Data APIs. If you're working with client libraries, please follow these instructions.
OAuth scope parameter
https://apps-apis.google.com/a/feeds/migration/
To use this system, you submit the email address, a password or the two-step verification access code of the domain user or administrator making the request. The authentication service returns an authentication token that your client can then send to the Email Migration API service along with every subsequent request on behalf of that user.
To obtain an authentication token, submit an HTTP POST request to the following URL:
https://www.google.com/accounts/ClientLogin
The POST body should contain a set of query parameters, as described in the following table. They should look like parameters passed by an HTML form, using the application/x-www-form-urlencoded content type.
| Parameter | Description |
|---|---|
Email |
The email address of the domain administrator or user. |
Passwd |
The domain administrator's or user's password. Or the domain administrator's access code if enrolled in two-step verification. |
accountType |
The string HOSTED, which indicates that this is an authorization for a hosted Google Account. |
service |
The string apps, which is the service name for Google Apps. |
If the authentication request fails, the server returns an HTTP 403 Forbidden status code.
If the request succeeds, then the server returns an HTTP 200 OK status code, plus three long alphanumeric codes in the body of the response: SID, LSID, and Auth. The Auth value is the authentication token that you'll send to the Email Migration API with your request, so keep a copy of that value. You can ignore the SID and LSID values.
Since all requests to Email Migration API feeds require authentication, you have to set the Authorization header in the request, using the following format:
Authorization: GoogleLogin auth=yourAuthToken
Where yourAuthToken is the Auth string returned by the authentication request.
Note: Authentication tokens expire after 24 hours. If an authenticated request fails, it may mean you need to acquire another token by posting the credentials to the ClientLogin URL again.
We recommend that you keep the token in memory rather than writing it to a file.
For information on how to handle a CAPTCHA challenge while obtaining an authentication token, see the following FAQ.
MailItemService object, and invoke its setUserCredentials method, as follows:
MailItemService mailItemService = new MailItemService("exampleCo-exampleApp-1");
mailItemService.setUserCredentials(userEmail, password);
Replace userEmail with the email address of the user to authenticate (usually an administrator) and password with that user's password or access code if enrolled in two-step verification.
MigrationService instance by passing in the following arguments:
migration_service = service.MigrationService(email=email, password=password,
domain=domain, source=app_name)
migration_service.ProgrammaticLogin()
Replace email with the email address of the user to authenticate (usually an administrator), password with that user's password or the user's access code if enrolled in two-step verification, domain with your domain name, and source with your client application's name, of the form companyName-applicationName-versionID.
MailItemService object, and invoke its setUserCredentials method, as follows:
MailItemService mailItemService = new MailItemService(domain, "Sample Migration Application"); mailItemService.setUserCredentials(userEmail, password or two-step verification access code);
Replace domain with your domain name, userEmail with the email address of the user to authenticate (usually an administrator), and password with that user's password or the user's access code if enrolled in two-step verification.
To migrate mail messages into a hosted Gmail account, issue multipart POST requests, where the first part contains an Atom entry specifying the message properties and labels, and the second part contains the complete RFC 822 message as UTF-8 text. Alternatively, you can use the client libraries to simplify the email migration.
Note: Base64 encoded RFC 822 message capability is now deprecated. The RFC 822 message should be UTF-8 text.
Content-Type: multipart/related;boundary="----=_Part_0_25934938.1266495790627"
------=_Part_0_25934938.1266495790627 Content-Type: application/atom+xml <?xml version='1.0' encoding='UTF-8'?><entry xmlns='http://www.w3.org/2005/Atom' xmlns:apps='http://schemas.google.com/apps/2006'> <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/apps/2006#mailItem'/> <atom:content xmlns:atom='http://www.w3.org/2005/Atom' type='message/rfc822'/> <apps:mailItemProperty value='IS_INBOX'/> </entry> ------=_Part_0_25934938.1266495790627 Content-Type: message/rfc822 MIME-Version: 1.0 Received: by 10.216.52.85 with HTTP; Thu, 18 Feb 2010 04:16:09 -0800 (PST) Date: Thu, 18 Feb 2010 17:46:09 +0530 Delivered-To: audit1@yourdomain.com Message-ID: <5db9e26e1002180416n9436618p2e828b22753764f9@mail.gmail.com> Subject: Hello Multipart HTTP From: anirudh dewani <audit1@yourdomain.com> To: audit user <audit2@yourdomain.com> Content-Type: multipart/alternative; boundary=0016e64c1c48a28a49047fdeee47 --0016e64c1c48a28a49047fdeee47 Content-Type: text/plain; charset=ISO-8859-1 This is a test mail using multipart HTTP requests for Email Migration API. Thanks. --0016e64c1c48a28a49047fdeee47 Content-Type: text/html; charset=ISO-8859-1 This is a test mail using multipart HTTP requests for Email Migration API.<div><br></div><div>Thanks.</div> --0016e64c1c48a28a49047fdeee47-- ------=_Part_0_25934938.1266495790627--
Include the following elements in the Atom entry:
<apps:mailItemProperty> elements, corresponding to properties that the server should apply to the message when the message is inserted into Gmail. The value attribute for each element must be one of the following:
IS_DRAFTIS_INBOXIS_SENTIS_STARREDIS_TRASHIS_UNREAD<apps:label> elements, corresponding to Gmail labels that should be applied to the message when it is inserted. In the example above, we're specifying that the message should have the "Friends" and "Event Invitations" labels in Gmail.Note: Batch insertion mode has been deprecated. We recommend that you use multi-threaded clients (one thread per user) with multipart HTTP requests to improve the speed of the process.
There are two different groups who can migrate mail:
If you are an end user migrating mail to your own mailbox, you can also use the "default feed" for convenience:
POST https://apps-apis.google.com/a/feeds/migration/2.0/default/mail
If your request is successful, the server returns a feed containing the inserted mail item entry.
Below is a sample RFC 822 email message. We recommend that you use a public library such as JavaMail to construct these messages. For more information about this format, including an explanation of how each field is interpreted, refer to the official RFC 822 standard definition.
MIME-Version: 1.0 Received: by 10.216.170.147 with HTTP; Fri, 26 Mar 2010 12:54:28 -0700 (PDT) Date: Sat, 27 Mar 2010 03:54:28 +0800 Delivered-To: darcy@example.com Message-ID: <203b3a4f1043461254v14855b71w9ce59e3abcf45962@mail.gmail.com> Subject: hello multipart From: Elizabeth Bennet <bennet@example.com> To: Fitzwilliam Darcy <darcy@example.com> Content-Type: multipart/alternative; boundary=000e0cdf7740f8017e0482b9877a --000e0cdf7740f8017e0482b9877a Content-Type: text/plain; charset=ISO-8859-1 howdy multipart! --000e0cdf7740f8017e0482b9877a Content-Type: text/html; charset=ISO-8859-1 howdy multipart! --000e0cdf7740f8017e0482b9877a--
Note: Each line in an RFC 822 message should be terminated by a CR+LF (that is, "\r\n") style newline.
MailItemEntry object for each message you're migrating, as demonstrated in the following example:
MailItemEntry entry = new MailItemEntry();
Rfc822MediaSource mediaSource = new Rfc822MediaSource(rfc822text);
entry.setMediaSource(mediaSource);
entry.addMailProperty(MailItemProperty.STARRED);
entry.addMailProperty(MailItemProperty.UNREAD);
entry.addLabel(new Label("Friends"));
entry.addLabel(new Label("Event Invitations"));
Set or add the following properties:
Rfc822MediaSource object, containing the RFC 822 content of the email message. (See below for an example.)MailItemProperty objects, corresponding to properties that the server should apply to the message when the message is inserted into Gmail. Each MailItemProperty must be one of the following:
MailItemProperty.DRAFTMailItemProperty.INBOXMailItemProperty.SENTMailItemProperty.STARREDMailItemProperty.TRASHMailItemProperty.UNREADLabel objects, corresponding to Gmail labels that should be applied to the message when it is inserted. In the example above, we're specifying that the message should have the "Friends" and "Event Invitations" labels in Gmail. If these labels don't already exist, they will now be created.It's possible to post a single mail item entry at a time, but in most cases when you're migrating mail you'll want to migrate multiple entries at once. We therefore recommend that you take advantage of Java multi-threading capabilities by creating one thread for each user's email and run many such threads for multiple users to increase your migration rate. Note that Email Migration API is rate limited per user and the server will respond with 503 - Server Busy if you migrate too fast. Read the troubleshooting section at the end of this guide to handle 503 HTTP return code.
If your request is successful, the server returns an HTTP 200 OK status code, plus the Atom entry containing the inserted mail item.
ImportMail method like so:
mail_item_properties = ['IS_INBOX', 'IS_STARRED']
mail_labels = ['Imported']
migration_service.ImportMail(user_name=username,
mail_message=content,
mail_item_properties=mail_item_properties,
mail_labels=mail_labels)
In a typical scenario, however, you will be migrating a bunch of mail messages from another account to Gmail, for which the multi-threading capabilities of the Python library will come good. The code below shows how to import a list of messages by iterating through each of its messages that contain an RFC 822 formatted string:
for message in messages:
migration_service.AddMailEntry(mail_message=message,
mail_item_properties=mail_item_properties,
mail_labels=mail_labels)
migration_service.ImportMultipleMails(user_name=username)
The attributes used in the above examples are defined below:
message is a string containing the RFC 822 content of the email message.mail_item_properties, corresponding to properties that the server should apply to the message when the message is inserted into Gmail. Each item in the list must have one of the following string values:
IS_DRAFTIS_INBOXIS_SENTIS_STARREDIS_TRASHIS_UNREADIn the first example above, we're telling the MigrationService that the message will be imported to the Gmail Inbox and starred.
mail_labels, corresponding to Gmail labels that should be applied to the message when it is inserted. Again, in the first example, we said that the imported message should have the "Imported" label in Gmail.MailItemEntry object for each message you're migrating, as demonstrated in the following example:
MailItemEntry entry = new MailItemEntry();
entry.Rfc822Msg = new Rfc822MsgElement(rfcTextOfMessage);
entry.MailItemProperties.Add(MailItemPropertyElement.STARRED);
entry.MailItemProperties.Add(MailItemPropertyElement.UNREAD);
entry.Labels.Add(new LabelElement("Friends"));
entry.Labels.Add(new LabelElement("Event Invitations"));
Set or add the following attributes:
Rfc822MsgElement object, containing the RFC 822 content of the email message.MailItemProperty objects, corresponding to properties that the server should apply to the message when the message is inserted into Gmail. Each MailItemProperty must be one of the following:
MailItemPropertyElement.DRAFTMailItemPropertyElement.INBOXMailItemPropertyElement.SENTMailItemPropertyElement.STARREDMailItemPropertyElement.TRASHMailItemPropertyElement.UNREADLabelElement objects, corresponding to Gmail labels that should be applied to the message when it is inserted. In the example above, we're specifying that the message should have the "Friends" and "Event Invitations" labels in Gmail.It's possible to post a single mail item entry at a time, but in most cases when you're migrating mail you'll be migrating multiple entries at once. We therefore recommend that you take advantage of the batch insertion feature of the Email Migration API, which greatly reduces the number of HTTP requests you have to make and thereby lowers your client's bandwidth.
To insert mail items in a batch, construct an array of MailItemEntry objects (named entries in the following example) and initialize each one as shown above. Then "tag" each entry with a batch ID to track the status of each one:
for (int i = 0; i < entries.Length; i++)
{
entries[i].BatchData = new GDataBatchEntryData();
entries[i].BatchData.Id = i.ToString();
}
Then post the entries as follows:
MailItemFeed feed = mailItemService.Batch(domain, username, entries);
If your request is successful, the server returns a feed containing the inserted mail item entries. You can check the batch status of each entry in the feed that's returned to determine if the insertion succeeded, as follows:
foreach (AtomEntry entry in batchResult.Entries)
{
GDataBatchEntryData batchData = entry.BatchData;
Console.WriteLine("Mail message {0}: {1} {2}",
batchData.Id, batchData.Status.Code, batchData.Status.Reason);
}
The client library ensures that characters in the message aren't interpreted as XML, so if you use the .NET client library, you don't need to worry about things like escaping the angle
brackets. However, if your message is encoded in a format other than plain ASCII, we recommend using Base64 encoding to ensure proper transmission. To do
this, supply the Base64-encoded form of the message in the Rfc822MsgElement constructor as follows:
new Rfc822MsgElement(base64EncodedMessage, Rfc822MsgElement.EncodingMethod.BASE64)
There are a variety of online tools and sample programs that demonstrate the process of encoding text in Base64. If you are using the .NET 2.0 Framework, you can also use the standard Convert.ToBase64String() method to perform the encoding.
Here are some notes about limits and error situations:
POST request.From:, To:, and Date: header fields required by the RFC822 specification. If a message is rejected as malformed, you'll receive a 400 Bad Request HTTP return code.503 Service Unavailable. If you receive
that status code, then retry uploading the failed entry. We recommend using an exponential backoff strategy for this process. For example, you might wait
thirty seconds and retry the upload; then if your request still returns 503s, wait 60 seconds before trying again, and so on.