### 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']*>' // After - limit to 128 characters r']{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 ); } ```