### Clone and Build cozy-stack CLI
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0061-cozy-integration-set-up.md
This sequence clones the cozy-stack repository, builds the CLI, and sets up the cozy configuration file by copying an example and updating the CouchDB URL.
```bash
git clone git@github.com:cozy/cozy-stack.git
cd cozy-stack
make
mkdir -p ~/.cozy
cp cozy.example.yaml $HOME/.cozy/cozy.yml
# Edit cozy.yml to set couchdb url:
couchdb:
url:
```
--------------------------------
### Setup Development Environment with Docker Compose
Source: https://github.com/linagora/tmail-flutter/blob/master/README.md
Steps to generate RSA keys for the backend and initialize the full-stack environment using Docker Compose.
```bash
openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:4096 -out jwt_privatekey
openssl rsa -in jwt_privatekey -pubout -out jwt_publickey
docker compose up -d
docker compose exec tmail-backend /root/provisioning/provisioning.sh
```
--------------------------------
### Install CouchDB using Docker
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0061-cozy-integration-set-up.md
This command installs and runs CouchDB in a Docker container, mapping port 5984 and persisting data in a local volume. It also initializes the necessary databases.
```bash
docker run -d \
--name cozy-stack-couch \
-p 5984:5984 \
-e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password \
-v $HOME/.cozy-stack-couch:/opt/couchdb/data \
couchdb:3.3
curl -X PUT http://admin:password@127.0.0.1:5984/{_users,_replicator}
```
--------------------------------
### Run cozy-stack and Create Instance
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0061-cozy-integration-set-up.md
These commands start the cozy-stack server and create a new Tmail instance with specified applications, domain, and email. The instance will be accessible at http://tmail.localhost:8080/ with the password 'cozy'.
```bash
cozy-stack serve
cozy-stack instances add tmail.localhost:8080 --passphrase cozy --apps home,store,drive,photos,settings,contacts,notes,passwords --email tmail@cozy.localhost --locale en --public-name Tmail --context-name dev
```
--------------------------------
### Run Cozy Locally with Tmail App
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0061-cozy-integration-set-up.md
This section details how to run the cozy-stack server with the Tmail app directory, install necessary Cozy applications and features, and configure Tmail for local development.
```bash
# On the cozy-twakemail side:
git clone https://github.com/cozy/cozy-twakemail
yarn install
yarn build
cozy-stack serve --appdir tmail:build/ --disable-csp
# In another terminal:
cozy-stack apps install dataproxy --domain tmail.localhost:8080
cozy-stack feature flags --domain tmail.localhost:8080 '{"cozy.search.enabled": true}'
cozy-stack feature flags --domain tmail.localhost:8080 '{"mail.embedded-app-url": "http://localhost:2023"}'
# On the tmail side:
# Apply patches/cozy-dev-config.patch
# Edit session url in jmap-dart-client to /jmap/session
# In cozy_config_web.dart, return true on isInsideCozy if run on localhost
# In env.file, set COZY_INTEGRATION=true and COZY_EXTERNAL_BRIDGE_VERSION=x.x.x
flutter run -d chrome --web-port 2023 --web-browser-flag "--disable-web-security" --profile
```
--------------------------------
### Install Xcode Command Line Tools
Source: https://github.com/linagora/tmail-flutter/blob/master/ios/fastlane/README.md
Installs the necessary Xcode command line tools required for building iOS applications. This is a prerequisite for running Fastlane commands.
```shell
xcode-select --install
```
--------------------------------
### Execute Prebuild Script
Source: https://github.com/linagora/tmail-flutter/blob/master/README.md
This script is part of the build process for the Twake Mail project, likely performing setup or configuration tasks before the main build commands are executed.
```bash
/bin/bash scripts/prebuild.sh
```
--------------------------------
### Build iOS Development Version
Source: https://github.com/linagora/tmail-flutter/blob/master/ios/fastlane/README.md
Triggers the Fastlane action to build the development version of the iOS application. It can be executed with or without bundle exec depending on the local environment setup.
```shell
[bundle exec] fastlane ios dev
```
--------------------------------
### Link Local Cozy Libraries for Development
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0061-cozy-integration-set-up.md
This process involves cloning cozy-libs, linking a modified package (e.g., cozy-external-bridge) locally, and then rebuilding and linking it into the cozy-twakemail project. This allows for live development of Cozy libraries used by Tmail.
```bash
# On cozy-libs side:
git clone https://github.com/cozy/cozy-libs
yarn install
yarn build
cd packages/cozy-external-bridge
yarn link
yarn build
# On cozy-twakemail side:
mv ~/Downloads/rlink.sh ~/bin/rlink
chmod +x ~/bin/rlink
# Reset terminal
# Repeat part 1 of 'Run Cozy locally'
# In another terminal in the same directory:
rlink cozy-external-bridge
yarn build
# On tmail side:
# Repeat part 2 of 'Run Cozy locally'
```
--------------------------------
### Mount Environment Configuration in Docker
Source: https://github.com/linagora/tmail-flutter/blob/master/README.md
Demonstrates how to override the default environment configuration by mounting a local file into the container at runtime.
```bash
docker run -d -ti -p 8080:80 --mount type=bind,source="$(pwd)"/env.dev.file,target=/usr/share/nginx/html/assets/env.file --name web tmail-web:latest
```
--------------------------------
### Deploy Twake Mail Web via Docker
Source: https://context7.com/linagora/tmail-flutter/llms.txt
Provides instructions for deploying the Twake Mail web application using Docker. Includes options for building images, mounting custom environment files, and orchestrating a full stack with Docker Compose.
```bash
# Option 1: Build with environment file
docker build -t tmail-web:latest .
docker run -d -p 8080:80 --name tmail-web tmail-web:latest
# Option 2: Mount custom environment at runtime
docker run -d -p 8080:80 \
--mount type=bind,source="$(pwd)"/env.custom.file,target=/usr/share/nginx/html/assets/env.file \
--name tmail-web linagora/tmail-web:latest
# Option 3: Full stack with docker-compose
openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:4096 -out jwt_privatekey
openssl rsa -in jwt_privatekey -pubout -out jwt_publickey
cd backend-docker
docker compose up -d
docker compose exec tmail-backend /root/provisioning/provisioning.sh
```
--------------------------------
### Configure Application Environment
Source: https://context7.com/linagora/tmail-flutter/llms.txt
The env.file configuration allows setting server URLs, OIDC authentication parameters, and feature flags for the application. This file is essential for environment-specific behavior and integration settings.
```bash
SERVER_URL=https://jmap.example.com/
DOMAIN_REDIRECT_URL=https://app.example.com
WEB_OIDC_CLIENT_ID=teammail-web
OIDC_SCOPES=openid,profile,email,offline_access
APP_GRID_AVAILABLE=supported
FCM_AVAILABLE=supported
IOS_FCM=supported
FORWARD_WARNING_MESSAGE=
COZY_INTEGRATION=
SENTRY_ENABLED=false
SENTRY_DSN=
```
--------------------------------
### Get All Emails with Query
Source: https://context7.com/linagora/tmail-flutter/llms.txt
Retrieves emails using JMAP query with filtering, sorting, and pagination support. This endpoint first queries for email IDs and then fetches the email details using a back-reference to the query results.
```APIDOC
## POST /jmap/mail/email/query
### Description
Retrieves emails using JMAP query with filtering, sorting, and pagination support. This endpoint first queries for email IDs and then fetches the email details using a back-reference to the query results.
### Method
POST
### Endpoint
/jmap/mail/email/query
### Parameters
#### Query Parameters
- **limit** (UnsignedInt) - Optional - The maximum number of emails to retrieve.
- **position** (int) - Optional - The starting position for retrieving emails.
- **sort** (Set) - Optional - The sorting criteria for the emails.
- **filter** (Filter) - Optional - The filtering criteria for the emails.
- **properties** (Properties) - Optional - The specific properties of the emails to retrieve.
### Request Example
```json
{
"accountId": "someAccountId",
"limit": 10,
"position": 0,
"sort": [{"property": "date", "dir": "DESC"}],
"filter": {"inMailbox": "someMailboxId"},
"properties": {"body": true, "headers": true}
}
```
### Response
#### Success Response (200)
- **state** (string) - The state of the email data.
- **list** (array) - A list of email objects.
#### Response Example
```json
{
"state": "someState",
"list": [
{
"id": "email1",
"subject": "Meeting Reminder",
"date": "2023-10-27T10:00:00Z"
},
{
"id": "email2",
"subject": "Project Update",
"date": "2023-10-26T15:30:00Z"
}
]
}
```
```
--------------------------------
### Get All Mailboxes with Properties - Dart
Source: https://context7.com/linagora/tmail-flutter/llms.txt
Retrieves all mailboxes for an account, including their properties like name, role, parent, and unread counts. It uses the GetMailboxMethod from the jmap_dart_client library. The function returns a JmapMailboxResponse containing the list of mailboxes and the state, or throws a NotFoundMailboxException if no mailboxes are found.
```dart
import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_method.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/get/get_mailbox_response.dart';
Future getAllMailbox(
Session session,
AccountId accountId,
{Properties? properties}
) async {
final processingInvocation = ProcessingInvocation();
final jmapRequestBuilder = JmapRequestBuilder(httpClient, processingInvocation);
final getMailboxMethod = GetMailboxMethod(accountId);
if (properties != null) {
getMailboxMethod.addProperties(properties);
}
final queryInvocation = jmapRequestBuilder.invocation(getMailboxMethod);
final result = await (jmapRequestBuilder
..usings(getMailboxMethod.requiredCapabilities))
.build()
.execute();
final getMailboxResponse = result.parse(
queryInvocation.methodCallId,
GetMailboxResponse.deserialize
);
if (getMailboxResponse != null && getMailboxResponse.list.isNotEmpty) {
return JmapMailboxResponse(
mailboxes: getMailboxResponse.list,
state: getMailboxResponse.state
);
} else {
throw NotFoundMailboxException();
}
}
```
--------------------------------
### Build and Run Twake Mail Web via Docker
Source: https://github.com/linagora/tmail-flutter/blob/master/README.md
Commands to build the Docker image from source and run the container. This assumes the environment file is correctly configured for the JMAP backend.
```bash
docker build -t tmail-web:latest .
docker run -d -ti -p 8080:80 --name web tmail-web:latest
```
--------------------------------
### Build Web App with Flutter
Source: https://github.com/linagora/tmail-flutter/blob/master/README.md
Instructions to build the web version of the Twake Mail application using Flutter. This process involves configuring the server URL and then running the build command.
```bash
SERVER_URL=http://your-jmap-server.domain
flutter build web
```
--------------------------------
### Get Email Content using JMAP in Dart
Source: https://context7.com/linagora/tmail-flutter/llms.txt
Retrieves the full content of an email, including HTML body, attachments, and headers, using the JMAP `Email/get` method. It requires a session, account ID, email ID, and optionally additional properties for fetching specific data. The function returns an `Email` object or throws a `NotFoundEmailException` if the email is not found.
```dart
import 'package:jmap_dart_client/jmap/mail/email/get/get_email_method.dart';
import 'package:jmap_dart_client/jmap/mail/email/get/get_email_response.dart';
Future getEmailContent(
Session session,
AccountId accountId,
EmailId emailId,
{Properties? additionalProperties}
) async {
final processingInvocation = ProcessingInvocation();
final jmapRequestBuilder = JmapRequestBuilder(_httpClient, processingInvocation);
final getEmailMethod = GetEmailMethod(accountId)
..addIds({emailId.id})
..addProperties(Properties({
'id', 'blobId', 'threadId', 'mailboxIds', 'keywords',
'subject', 'from', 'to', 'cc', 'bcc', 'replyTo',
'sentAt', 'receivedAt', 'hasAttachment', 'preview',
'htmlBody', 'bodyValues', 'attachments'
}))
..addFetchHTMLBodyValues(true);
final getEmailInvocation = jmapRequestBuilder.invocation(getEmailMethod);
final result = await (jmapRequestBuilder
..usings(getEmailMethod.requiredCapabilities))
.build()
.execute();
final resultList = result.parse(
getEmailInvocation.methodCallId,
GetEmailResponse.deserialize
);
if (resultList?.list.isNotEmpty == true) {
return resultList!.list.first;
} else {
throw NotFoundEmailException();
}
}
```
--------------------------------
### Build Android App with Flutter
Source: https://github.com/linagora/tmail-flutter/blob/master/README.md
Instructions to build the Android application (APK) using Flutter. This command compiles the Flutter project into an Android package.
```bash
flutter build apk
```
--------------------------------
### Configure App Grid for Multi-Service Navigation
Source: https://context7.com/linagora/tmail-flutter/llms.txt
Defines the structure of the application dashboard using a JSON configuration file. It maps application names, icons, and deep-linking parameters for both Android and iOS platforms.
```json
{
"apps": [
{
"appName": "Twake Chat",
"icon": "ic_twake_app.svg",
"appLink": "https://chat.example.com/",
"androidPackageId": "com.example.chat",
"iosUrlScheme": "twakechat",
"iosAppStoreLink": "https://apps.apple.com/app/id123456789"
},
{
"appName": "Drive",
"icon": "ic_drive_app.svg",
"appLink": "https://drive.example.com/",
"androidPackageId": "com.example.drive",
"iosUrlScheme": "twakedrive",
"publicIconUri": "https://cdn.example.com/icons/drive.svg"
}
]
}
```
--------------------------------
### Create One-Time Work Request with WorkManager
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0028-use-work-manager-to-mange-task-scheduling.md
This code shows how to create a 'OneTimeWorkRequest' for tasks that should only be executed once. It allows for optional parameters like initial delay, backoff policies, and constraints.
```dart
final workReuest = OneTimeWorkRequest(
worker,
Duration? initialDelay,
Duration? backoffPolicyDelay,
ExistingWorkPolicy? existingWorkPolicy,
BackoffPolicy? backoffPolicy,
OutOfQuotaPolicy? outOfQuotaPolicy,
Constraints? constraints
);
```
--------------------------------
### Optimize Regex Patterns with Bounded Quantifiers
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0069-redos-vulnerability-mitigation.md
Demonstrates replacing unbounded quantifiers with specific bounds to prevent catastrophic backtracking in HTML tag matching.
```dart
// Before
r'[a-zA-Z][^>]*>'
// After - limit to 128 characters
r'[a-zA-Z][^>]{0,128}>'
```
--------------------------------
### Enqueue Work Request with WorkManager
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0028-use-work-manager-to-mange-task-scheduling.md
This code shows how to add a 'WorkRequest' to the WorkManager's queue for execution. The 'enqueue' method handles scheduling the task based on its type and defined constraints.
```dart
await WorkSchedulerController().enqueue(workReuest);
```
--------------------------------
### Initialize WorkManager in Flutter
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0028-use-work-manager-to-mange-task-scheduling.md
This code demonstrates the initialization of the WorkManager service within your Flutter application. This step is crucial before scheduling any background tasks.
```dart
await WorkManagerConfig().initialize();
```
--------------------------------
### Optimize String Processing and Regex Patterns in Dart
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0069-redos-vulnerability-mitigation.md
Demonstrates techniques to reduce computational overhead by eliminating redundant string passes, using early exit loops, and applying guard clauses before executing expensive regex operations.
```dart
// Before - unnecessary preprocessing
final listStrings = input
.replaceAll('\n', ' ') // Extra pass through string
.split(separator)
.map((value) => value.trim()) // Extra iteration
.where((value) => value.isNotEmpty)
.toList();
// After - include newlines in separator pattern
static const String emailSeparatorPattern = r'[ ,;\n\r\t]+';
final listStrings = input
.split(separator)
.where((value) => value.isNotEmpty)
.toList();
```
```dart
// Before - check all lines twice
final isMarkdown = lines.any((line) => mdSeparatorRegex.hasMatch(line));
final isAsciiArt = lines.every((line) => asciiArtRegex.hasMatch(line));
// After - single pass with early exit
for (final line in lines) {
if (!isMarkdown && _mdSeparatorRegex.hasMatch(line)) {
isMarkdown = true;
}
if (allLinesHaveAscii && !_asciiArtRegex.hasMatch(line)) {
allLinesHaveAscii = false;
}
if (isMarkdown && !allLinesHaveAscii) break; // Early exit
}
```
```dart
// Before - regex always runs
if (input.length % 4 == 0 && input.contains(RegExp(r'^[A-Za-z0-9+/=]+$'))) {
// After - cheap checks first, regex only if necessary
if (input.length % 4 == 0 && !input.contains(' ')) {
if (_base64ValidationRegex.hasMatch(input)) {
// expensive decoding
}
}
```
--------------------------------
### Create Periodic Work Request with WorkManager
Source: https://github.com/linagora/tmail-flutter/blob/master/docs/adr/0028-use-work-manager-to-mange-task-scheduling.md
This snippet demonstrates the creation of a 'PeriodicWorkRequest' for tasks that need to run at regular intervals. Similar to one-time requests, it supports various configuration options.
```dart
final workReuest = PeriodicWorkRequest(
worker,
Duration? frequency,
Duration? initialDelay,
Duration? backoffPolicyDelay,
ExistingWorkPolicy? existingWorkPolicy,
BackoffPolicy? backoffPolicy,
OutOfQuotaPolicy? outOfQuotaPolicy,
Constraints? constraints
);
```
--------------------------------
### Search Emails with Snippets
Source: https://context7.com/linagora/tmail-flutter/llms.txt
Searches emails and retrieves search snippets highlighting matched terms. This endpoint performs an email query, retrieves search snippets, and then fetches the email details.
```APIDOC
## POST /jmap/mail/email/searchSnippet/get
### Description
Searches emails and retrieves search snippets highlighting matched terms. This endpoint performs an email query, retrieves search snippets, and then fetches the email details.
### Method
POST
### Endpoint
/jmap/mail/email/searchSnippet/get
### Parameters
#### Query Parameters
- **limit** (UnsignedInt) - Optional - The maximum number of emails to retrieve.
- **sort** (Set) - Optional - The sorting criteria for the emails.
- **filter** (Filter) - Optional - The filtering criteria for the emails.
- **properties** (Properties) - Optional - The specific properties of the emails to retrieve.
### Request Example
```json
{
"accountId": "someAccountId",
"limit": 5,
"filter": {"text": "important"},
"properties": {"subject": true}
}
```
### Response
#### Success Response (200)
- **state** (string) - The state of the email data.
- **emailList** (array) - A list of email objects.
- **searchSnippets** (array) - A list of search snippet objects.
#### Response Example
```json
{
"state": "someState",
"emailList": [
{
"id": "email3",
"subject": "Important Announcement"
}
],
"searchSnippets": [
{
"emailId": "email3",
"snippet": "This is an **important** announcement regarding..."
}
]
}
```
```
--------------------------------
### Build iOS App with Flutter
Source: https://github.com/linagora/tmail-flutter/blob/master/README.md
Instructions to build the iOS version of the Twake Mail application using Flutter. This command compiles the Flutter project into an iOS application.
```bash
flutter build ios
```
--------------------------------
### Retrieve All Emails with Query (Dart)
Source: https://context7.com/linagora/tmail-flutter/llms.txt
Fetches all emails based on a JMAP query, supporting filtering, sorting, and pagination. It first queries for email IDs and then retrieves the full email details using back-references. Requires session, account ID, and optional query parameters.
```dart
import 'package:jmap_dart_client/jmap/mail/email/query/query_email_method.dart';
Future getAllEmail(
Session session,
AccountId accountId,
{
UnsignedInt? limit,
int? position,
Set? sort,
Filter? filter,
Properties? properties
}
) async {
final processingInvocation = ProcessingInvocation();
final jmapRequestBuilder = JmapRequestBuilder(httpClient, processingInvocation);
// Step 1: Query for email IDs
final queryEmailMethod = QueryEmailMethod(accountId);
if (limit != null) queryEmailMethod.addLimit(limit);
if (position != null && position > 0) queryEmailMethod.addPosition(position);
if (sort != null) queryEmailMethod.addSorts(sort);
if (filter != null) queryEmailMethod.addFilters(filter);
final queryEmailInvocation = jmapRequestBuilder.invocation(queryEmailMethod);
// Step 2: Get email details using back-reference to query results
final getEmailMethod = GetEmailMethod(accountId);
if (properties != null) getEmailMethod.addProperties(properties);
getEmailMethod.addReferenceIds(
processingInvocation.createResultReference(
queryEmailInvocation.methodCallId,
ReferencePath.idsPath
)
);
final getEmailInvocation = jmapRequestBuilder.invocation(getEmailMethod);
final result = await (jmapRequestBuilder
..usings(getEmailMethod.requiredCapabilities))
.build()
.execute();
final getEmailResponse = result.parse(
getEmailInvocation.methodCallId, GetEmailResponse.deserialize);
final queryEmailResponse = result.parse(
queryEmailInvocation.methodCallId, QueryEmailResponse.deserialize);
return EmailsResponse(
emailList: getEmailResponse?.list ?? [],
state: getEmailResponse?.state
);
}
```