Skip to content

Instantly share code, notes, and snippets.

@acidprime
Created December 3, 2014 07:11
Show Gist options
  • Save acidprime/12a5cf9e96dca255b7a5 to your computer and use it in GitHub Desktop.
Save acidprime/12a5cf9e96dca255b7a5 to your computer and use it in GitHub Desktop.
My old Mail.app configuration script
#!/bin/bash
#################################################################################
# Mail Configuration Script Tiger Ed. v10.4.X version 0.139 Updated 11/12/06 #
#################################################################################
# #
# #### #
# #### papers (a) wallcity.org #
# #### #### #
# #### #### papers.wallcity.org #
# #### #### #### #
# #### #### #### Zachary Smith #
# #### #### #### #
# #### #### #### ACTC,ACSA,ACN,ACT #
# #
#################################################################################
# CVS: $Header$ #
#################################################################################
# HEADER #
#################################################################################
# shopt -s -o nounset
# Check for unset variables in script
# shopt -s -o monitor
# enable job control in script?
# Print usage.
USAGE() {
printf "%s\n\t" "USAGE:"
printf "%s\n\t" " ALL MAIL SERVERS:"
printf "%s\n\t" " -n | -new <type> ## inject config for server of type IMAP POP or EXG"
printf "%s\n\t" " -i | -incoming <servername>:<port> ## Port is optional,defaults to standard for connection and encryption."
printf "%s\n\t" " -o | -outoing <servername>:<port> ## Port is optional,defaults to standard for connection and encryption."
printf "%s\n\t" " -s | -same <servername> ## Use same server for in/out port defaults to standard for connection and encryption."
printf "%s\n\t"
printf "%s\n\t" " OPTIONAL FOR EXCHANGE SERVER:"
printf "%s\n\t" " -u | -url \"http://<servername>:<port>/exchange/\" ## configure OWA server defaults to <servername>/exchange"
printf "%s\n\t"
printf "%s\n\t" " ALL SERVERS:"
printf "%s\n\t" " -e | -encryption ## Use SSL encryption for Mail Host"
printf "%s\n\t" " -E | -encryptall ## Use SSL encryption for Mail and LDAP"
printf "%s\n\t" " -a | -authentication <type> PASS MD5 KRB4 NTLM KRB5"
printf "%s\n\t" " -p | -path </path/to/Users/> ## Path to homedirectory location, use \"CONSOLE\" for console user."
printf "%s\n\t"
printf "%s\n\t" " LDAP SERVER:"
printf "%s\n\t" " -l | ldap <servername>:<port> ## Port is optional,defaults to standard for connection and encryption."
printf "%s\n\t" " -L | -ldapurl configure ldap server: \"<ldaps://><servername>:<port>/<searchbase>/\" ## Must be in correct format."
printf "%s\n\t"
printf "%s\n\t" " OTHER TASKS:"
printf "%s\n\t" " -t | -template </path/to/save> ## Save configuration to a template"
printf "%s\n\t" " -c | -createpkg </path/to/newinstaller.pkg> ## Create a mail config package installer ( Dev Tools Must Be installed )"
printf "%s\n\t" " -f | -file </path/to/mailconfig.conf> ## Read configuration from a file."
printf "%s\n\t" " -m | -manual ## Configure script manually with an option to save config file."
printf "%s\n\t" " -h | -help ## Print this usage message and quit."
printf "%s\n\t" " -d | -directory </Active Directory/All Domains/> ## /LDAPv3/127.0.0.1/"
printf "%s\n\t" " -r | -remotedirectory ##"
printf "%s\n\t"
printf "%s\n\t" " EXAMPLE TASKS:"
printf "%s\n\t" " sudo $0 -n IMAP -i mail.mycompany.com -o smtp.mycompany.com -a MD5 -e -p /Users/"
printf "%s\n\t" " sudo $0 -u \"https://winmail.mycompany.com:443/exchange/\" -a NTLM -p /Users/"
printf "%s\n\t" " sudo $0 -L \"ldaps://ldap.mycompany.com:636/dc=mycompany,dc=com\" -a NTLM -p /Users/"
printf "%s\n\t" " sudo $0 -n IMAP -i mail.mycompany.com -o smtp.mycompany.com -a MD5 -e -p /Users/ -c /path/to/saved.pkg"
printf "%s\n"
} # END USAGE
# DIE function.
DIE(){
declare LASTEXIT="$2"
CLEAN_UP || printf "%s\n" "ERROR: Unknown ERROR cleaning up"
USAGE >&2 # Print Usage.
printf "%s\n\v" "" "$1" >&2 # Print specifific error message for respective issue to standard error.
exit "${LASTEXIT:="192"}" # Exit with last status or 192 if non.
return 0
} # END DIE
CLEAN_UP () {
# Clean up of our variables
unset ${!REQ*}
unset ${!EXG*}
unset ${!MAIL*}
unset ${!LDAP*}
unset ${!INPUT*}
# -- Clean up our Functions
unset -f INJECT_LAUNCHD
unset -f DIE
return 0
printf "$SCRIPT ran in $SECONDS seconds"
} # END CLEAN_UP
# Run manual Interactive configurtion.
RUN_MANUAL() {
# First we must determine what type of Mail Server we are configuring.
printf "Starting Manual Configuration mode please enter <varibles> or hit return for [default]\n"
read -p "Please enter in the mail server's type <EXG> ,<POP>, or [IMAP]:" INPUT_MAILTYPE
QUESTIONS_ALL() {
read -p "Please enter in the incoming mail server's hostname [${INPUT_MAILHOST:-"mail.example.com"}] :" INPUT_MAILHOST
read -p "Please select the mail authentication type [${INPUT_MAILAUTH:-"PASSWORD"}]:" INPUT_MAILAUTH
read -p "Connect to server using SSL/TLS [YES]:"
read -p "Please enter in the incoming mail server's port [${GUESS_MAILPORT}] :" INPUT_MAILPORT
printf "%s\n" "Mail server's port set to:${INPUT_MAILPORT:=$GUESS_MAILPORT}" # If user hits return we use $GUESS_MAILPORT
} # END QUESTIONS_ALL
QUESTIONS_SMTP() {
read -p "Please enter in the outgoing mail server's hostname [${INPUT_SMTPHOST:-"smtp.exmple.com"}]:\n" INPUT_SMTPHOST
read -pn 6 "Please enter in the smtpoing mail server's port [${GUESS_MAILPORT}] :\n" INPUT_SMTPPORT
declare -i GUESS_SMTPPORT="25"
} # END QUESTIONS_SMTP
case $INPUT_MAILTYPE in
EXG | exg ) declare -x GUESS_MAILPORT="80" ; QUESTIONS_ALL || DIE "ERROR:$FUNCNAME: Unknown ERROR setting asking for input: EXG." 192 ;;
IMAP | imap ) declare -x GUESS_MAILPORT="143" ; QUESTIONS_ALL || DIE "ERROR:$FUNCNAME: Unknown ERROR setting asking for input: IMAP." 192 ;;
POP | pop ) declare -x GUESS_MAILPORT="110" ; QUESTIONS_ALL || DIE "ERROR:$FUNCNAME: Unknown ERROR setting asking for input: POP." 192 ;;
*) declare -x GUESS_MAILPORT="143" ; QUESTIONS_ALL || DIE "ERROR:$FUNCNAME: Unknown ERROR setting asking for input: IMAP." 192 ;;
esac
return 0
} # END RUN_MANUAL
CREATE_CONFIG(){
read -p "Where would you like to save the configuration file [${RUNDIRECTORY}/mailconfig.conf]:\n" SAVELOCATION
for CONFIGS in ${!INPUT*}; do # Glob and Grab all the varibles specified
echo "echo declare -x $CONFIGS=""\"\$${CONFIGS}\" | $sed 's/=/=\"/' | $sed 's/$/\"/g'>${SAVELOCATION:=$RUNDIRECTORY}/mailconfig.conf" >"${SAVELOCATION:=$RUNDIRECTORY}/mailconfig_unint.conf" # export varibles to source file
source "${SAVELOCATION:=$RUNDIRECTORY}/mailconfig_unint.conf" # Source the file and initialize the variables
done
printf "%s\n" "date +DATE: %m/%d/%y%nTIME: %H:%M:%S" > ${SAVELOCATION:=$RUNDIRECTORY}/mailconfig.conf
unset SAVELOCATION
} # END CREATE_CONFIG
# Set type
SET_MAILTYPE(){
case "$1" in # Pass the run-time postional parameter to the function.
# -n <type> ## configure new mail server of type IMAP POP EXG
IMAP | imap ) declare -x INPUT_MAILTYPE="IMAPAccount" CONFIG_MAIL="YES" ;;
POP | pop ) declare -x INPUT_MAILTYPE="POPAccount" CONFIG_MAIL="YES" ;;
EXG | owa ) declare -x INPUT_MAILTYPE="ExchangeAccount" CONFIG_EXG="YES" ;; # Need check for template as it doesnt officially support exchange.
* ) DIE "ERROR:$FUNCNAME: Unknown option for new mail server type: $1" 192 ;; # Die clause for unknown options.
esac
return 0
} # END SET_MAILTYPE
SET_AUTHTYPE() {
case "$1" in # Pass the run-time postional parameter to the function
PASS | pass ) declare -x INPUT_MAILAUTH="Password" ;; # Set the Password to type to Password
NTLM | ntlm ) declare -x INPUT_MAILAUTH="NTLM";; # Set the Password type to NT Lan Manager
MD5 | md5 ) declare -x INPUT_MAILAUTH="CRAM-MD5";; # Set the Password to CRAM-MD5 Challage Response
KRB4 | krb4 ) declare -x INPUT_MAILAUTH="KERBEROS_V4";; # Set The Password type Keberbos v4
KRB5 | krb5 ) declare -x INPUT_MAILAUTH="GSSAPI";; # Set the Password type to Kerberos v5 (GSSAPI)
*) DIE "ERROR:$FUNCNAME: Unknown option for mail authentication: $1" 192 ;; # Die clause for unknown options.
esac
return 0
} # END SET_AUTHTYPE
SET_SCOPE(){
case "$1" in # Pass the run-time postional parameter to the function.
BASE | base ) declare -x INPUT_LDAPSCOPE="1" ;;
ONE | one ) declare -x INPUT_LDAPSCOPE="2" ;;
SUB | sub ) declare -x INPUT_LDAPSCOPE="3" ;;
*) DIE "ERROR:$FUNCNAME:$LINENO Unknown option for LDAP scope: $1" 192 ;; # Die clause for unknown options.
esac
return 0 # All is well
} # END SET_SCOPE
# Set home path for injection of LDAP,MAIL or FOO
SET_HOMEPATH(){
case "$1" in
LOCAL | local ) HOMEPATH="/Users";;
NETWORK | local ) HOMEPATH;;
* ) declare -x HOMEPATH="$1";;
esac
} # END SET_HOMEPATH
SET_TEMPLATE_PATH(){
case "$1" in
CONSOLE | console ) declare -x TEMPLATEPATH="${HOMPATH}/${CONSOLEUSER:?There does does not seem to be a console user!}/Library/Mail/AccountTypes/${MAILIDFR}/MailAccounts.plist";;
LOCAL | local ) declare -x TEMPLATEPATH="${DSTROOT}Library/Mail/AccountTypes/${MAILIDFR}/MailAccounts.plist";;
* ) declare -x TEMPLATEPATH="${1}${MAILIDFR}/MailAccounts.plist";;
esac
return 0 # All is well
} # END SET_TEMPLATE_PATH
PARSE_EXGURL(){
URL_PREFIXHOSTPORT="${1%\/*}"
URL_PREFIX="${1%\/\/*}"
URL_PORT="${URL_PREFIXHOSTPORT#*:*:}"
URL_PREFIXHOST="${URL_PREFIXHOSTPORT%:*}"
URL_HOST="${URL_PREFIXHOST#http*:\/\/}"
return 0 # All is well
} # END PARSE_EXGURL
PARSE_LDAPURL(){
URL_PREFIXHOSTPORT="${1%\/*}"
URL_PREFIX="${1%\/\/*}"
URL_PORT="${URL_PREFIXHOSTPORT#*:*:}"
URL_PREFIXHOST="${URL_PREFIXHOSTPORT%:*}"
URL_HOST="${URL_PREFIXHOST#ldap*:\/\/}"
URL_SEARCHBASE="${1#ldap*:*\/\/*/}"
if [ "$URL_PREFIX" = "ldaps:" ] ; then
declare -x INPUT_LDAPSSL="true"
elif [ "$URL_PREFIX" = "ldap:" ] ; then
declare -x INPUT_LDAPSSL="false"
fi
declare -x INPUT_LDAPHOST="$(${OPTARG})"
declare -x INPUT_LDAPBASE="${OPTARG#ldap*:*\/\/*/}"
return 0 # All is well
} # END PARSE_LDAPURL
# Standard Bash Check
[ ! -z "$BASH" ] || DIE "ERROR: Please run this script with the bash shell" 192
# Check to see if script is running as root.
[ $EUID = 0 ] || DIE "ERROR: This script requires root privileges, you are user: $(/usr/bin/whoami)" 192
if [ "$SCRIPT_NAME" != "postflight" ] ; then # PACKAGE INSTALLER TEST
# Check to see if we are running as a postflight script,the installer creates the $SCRIPT_NAME variable
while [[ $1 = -* ]]; do # Grab all the Options ( postial paramaeters ) no getopts for lots of reasons.
case "$1" in
# -- EXCHANGE SERVER (OPTIONAL)
-n | -new ) shift; SET_MAILTYPE "$1" declare -x CONFIG_MAIL="YES" || DIE "ERROR:$SCRIPT:SET_MAILTYPE:$LINENO ERROR setting mail type." 192 ;; # Run Function for mailtype
-u | -url ) shift; declare -x CONFIG_EXG="YES"; PARSE_EXGURL "$1" || DIE "ERROR:$SCRIPT:PARSE_EXGURL:$LINENO Unknown ERROR setting parsing exchange URL" 192 ;; # As a time saver you can specify the OWA Url "http://exchange.mycompany.com/exchange/"
# -- ALL MAIL SERVERS options for all mail servers.
-p | -path ) shift; declare -x HOMEPATH="$1" # -p
[ -z "$HOMEPATH" ] || [[ "$HOMEPATH" = -* ]] && DIE "ERROR: You must specify a path to home directories for injection." 192 ;;
-i | -incoming ) shift; declare -x INPUT_MAILHOST="$1" # -i <server hostname>:<port> ## Incoming mail server specification.
[ -z "$INPUT_MAILHOST" ] || [[ "$INPUT_MAILHOST" = -* ]] && DIE "ERROR: Incoming mail host not specified." 192
[ $INPUT_MAILHOST = "${INPUT_MAILHOST#*:}" ] || declare -x INPUT_MAILPORT="${INPUT_MAILHOST#*:}";; # Extract port from argument.
-o | -outgoing ) shift; declare -x INPUT_SMTPHOST="$1" CONFIG_SMTP="YES" # -o <server hostname>:<port> ## Outgoing
[ -z "$INPUT_MAILHOST" ] || [[ "$INPUT_MAILHOST" = -* ]] && DIE "ERROR: Outgoing mail host not specified." 192
[ $INPUT_SMTPHOST = "${INPUT_SMTPHOST#*:}" ] || declare -x INPUT_SMTPPORT="${INPUT_SMTPHOST#*:}";; # Extract port from argument.
-s | -same ) shift; declare -x INPUT_SMTPHOST="${1%:*}" INPUT_MAILHOST="${1%:*}"
[ -z "$INPUT_MAILHOST" ] || [[ "$INPUT_MAILHOST" = -* ]] && DIE "ERROR: Outgoing mail host not specified." 192 ;;# Leaving off ports of entered as they are different services.
-a | -authentication ) shift; MAILAUTH "$1" || DIE "ERROR:$SCRIPT:MAILAUTH:$LINENO Unknown ERROR setting authentication type" 192# -a <type> PASS MD5 NTLM KRB4 KRB5
[ -z "$MAILAUTH" ] || [[ "$MAILAUTH" = -* ]] && DIE "ERROR: Mail authentication method not specified." 192 ;;
-e | -encrypt ) declare -x INPUT_MAILSSL="true" ;; # -e KERBEROS_V4 CRAM-MD5 NTLM GSSAPI
-E | -encyptall ) shift; declare -x INPUT_MAILSSL="true" INPUT_LDAPSSL="true" INPUT_EXGSSL="true" INPUT_EXGPORT="443" INPUT_IMAPPORT="993" INPUT_POPPORT="995" ;;
# -- LDAP SWITCHES:
-l | -ldap ) shift; declare -x INPUT_LDAPHOST="$1" CONFIG_LDAP="YES"
[ -z "$INPUT_LDAPHOST" ] || [[ "$INPUT_LDAPHOST" = -* ]] && DIE "ERROR: LDAP host not specified." 192 ;;
-L | -ldapurl ) shift; PARSE_LDAPURL "$1" || DIE "ERROR:$SCRIPT:PARSE_LDAPUR:$LINENO Unknown ERROR parsing LDAP URL" 192 ;;
-s | -scope ) shift; SET_SCOPE "$1" ;; # -scope <type> BASE ONE SUB
-b | -base ) shift; declare -x INPUT_LDAPBASE="$1" # -b | -base search base
[ -z "$INPUT_LDAPBASE" ] || [[ "$INPUT_LDAPBASE" = -* ]] && DIE "ERROR: LDAP search base not specified." 192 ;;
# -- OTHER TASKS:
-m | -manual )shift; RUN_MANUAL "$1" || DIE "ERROR:RUN_MANUAL: Unknown ERROR running manual configuration." 192 ;; # Run interactive "Manual" setup using read statements
-c | -createpkg ) declare -x INPUT_PKGLOC="$1" || DIE "ERROR: Package path must end with .pkg i.e. /Users/Shared/mailconfig.pkg" ;;
-t | -template ) INSTALL_TEMPLATE || DIE "ERROR:$SCRIPT:PARSE_LDAPUR:$LINENO Unknown ERROR installing template.";;
-h | -help ) USAGE; CLEAN_UP; exit 1 ;;
-z ) DIE "INFO: This script brought to you by Zack Smith email: zack (a) wallcity.org" ;;
*) DIE "ERROR: ${SCRIPT} : Unimplemented option specified \"$1\"" ;;
esac
done
elif
[ $# = 0 ] && USAGE >&2 && exit 1 # If we are not running postflight and no parameters given, print usage to stderr and exit status 1
else
printf "%s\n" "Running script in postflight package mode."
delcare -x PKGBUNDLE="${1}" # Full path to the install package.
declare -x DSTROOT="${3}" # Installation Volme of mount point.
declare -x SYSROOT="${4}" # The root directory for the system.
fi # END PACKAGE INSTALLER TEST
# -- Required Folders
CHECK_FOLDERS() {
if [ -f "${REQFLD}" ] ; then
DIE "ERROR:$FUNCNAME: The required folder ${REQFLD} is not found." 192
elif [ -w "${REQFLD}" ] ; then
DIE "ERROR:$FUNCNAME: The required folder ${REQFLD} is not writeable by user $($whoami)" 192
else
declare -x READYTOGO="yes"
fi
}
##########################################################
# GLOBAL DECLARATIONS #
##########################################################
CHECK_CONFIGFILE() {
if [ ! -f "${SETTINGS:=$RUNDIRECTORY/mailconfig.conf}" ] ; then
printf "%s\n" "$SCRIPT: the file $CONFIGFILE is not available" >&2
else
source "$CONFIGFILE" || DIE "ERROR: unable to parse config file: $CONFIGFILE, possibly does not have \"return 0\" on the last line."
fi
return 0
}
# -- Envoirmental settings
declare -x SCRIPTPATH="${0}"
declare -x SCRIPT="${0##*/}"
declare -x RUNDIRECTORY="${0%%/*}"
declare -x SYSROOT="/" DSTROOT="/"
# -- Required Executables
declare -rx awk="/usr/bin/awk"
declare -rx cp="/bin/cp"
declare -rx chown="/usr/sbin/chown"
declare -rx date="/bin/date"
declare -rx defaults="/usr/bin/defaults"
declare -rx uuidgen="/usr/bin/uuidgen"
declare -rx grep="/usr/bin/grep"
declare -rx ldapsearch="/usr/bin/ldapsearch"
declare -rx ls="/bin/ls"
declare -rx openssl="/usr/bin/openssl"
declare -rx mkdir="/bin/mkdir"
declare -rx mv="/bin/mv"
declare -rx sed="/usr/bin/sed"
declare -x REQCMDS="$awk $cp $chown $date $defaults $uuidgen $grep $ldapsearch $ls $openssl $perl $mv $sed $who" # $packagemaker caught in CREATE_PKG
# -- Optional Executables
declare -x packagemaker="/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker"
declare -x OSFLAVOR="CLIENT" ; [ ! -f /System/Library/CoreServices/ServerVersion.plist ] || declare -x OSFLAVOR="SERVER" # Check for client or server.
declare -x OSVER="`$defaults read "${SYSROOT}System/Library/CoreServices/SystemVersion" ProductVersion `"
declare -x CONFIGFILE="${RUNDIRECTORY:=/tmp}/mailconfig.conf"
declare -x UTCDATE=$($date -u "+%Y-%m-%dT%H:%M:%SZ")
declare -x UUIDGEN=$($uuidgen)
declare -x SCRIPTLOG="${DSTROOT}Library/Preferences/mailconfig.log"
# -- LDAP Servers
if [ "$CONFIG_LDAP" = "YES" ] ; then
declare -r LDAPUUID="$($uuidgen)"
declare -x LDAPHOST="${INPUT_LDAPHOST:?"ERROR:The LDAP server must be defined."}"
declare -x LDAPSSL="${INPUT_LDAPSSL:="false"}"
declare -x LDAPPORT="${INPUT_LDAPHOST:="389"}"
declare -x LDAPBASE="${INPUT_LDAPBASE%\./,dc=}"
declare -x LDAPSCOPE="${INPUT_LDAPSCOPE:=2}"
# -- Active Directory LDAP
declare -x ADLDAPHOST="$LDAPHOST"
declare -x ADLDAPPORT="$LDAPPORT"
declare -x ADLDAPBASE="$LDAPBASE"
# -- Open Directory LDAP
declare -x ODLDAPHOST="$LDAPHOST"
declare -x ODLDAPPORT="$LDAPPORT"
declare -x ODLDAPBASE="$LDAPBASE"
declare -x EXCLUDEDUSERS="$INPUT_EXUSERS"
fi
# -- All Mail Servers.
[ "$CONFIG_IMAP" = "YES" ] && declare -x MAILSRVPORT="${INPUT_IMAPPORT:=143}" # Defaults to standard IMAP 143 unless encryption is turned on.
[ "$CONFIG_POP" = "YES" ] && declare -x MAILSRVPORT="${INPUT_POPPORT:=110}" # Defaults to standard POP 110 unless encryption is turned on.
[ "$CONFIG_EXG" = "YES" ] && declare -x MAILSRVPORT="${INPUT_EXGPORT:=80}" # Defaults to standard OWA 80 unless encryption is turned on.
# -- IMAP and POP Servers
if [ "$CONFIG_MAIL" = "YES" ] ; then
declare -x MAILTYPE="${INPUT_MAILTYPE:?"ERROR:The mail type <EXG> <IMAP> <POP> must be defined."}"
declare -x MAILHOST="${INPUT_MAILHOST:?"ERROR:The mail host must be defined."}"
declare -x MAILNAME="${INPUT_MAILNAME:=INPUT_MAILHOST}"
declare -x MAILDOMAIN="${INPUT_MAILDOMAIN}"
declare -x MAILIDFR="$(echo $INPUT_MAILHOST | $awk -F . '{print $3"."$2"."$1}' | $sed 's/^[.]//g')" # Change mail.example.com to com.example.mail
declare -x MAILAUTH="${INPUT_MAILAUTH:?"ERROR:The mail authentication method must be defined."}" # Catch for required varible
declare -x MAILSSL="${INPUT_MAILSSL:=false}" # Defalts to false unless specified by the user.
declare -x MAILPORT="${INPUT_MAILPORT:=$MAILSRVPORT}" # Defaults to standard/encrypted unless user specified one.
fi
# -- Exchange Servers
if [ "$CONFIG_EXG" = "YES" ] ; then
declare -x EXGTYPE="$INPUT_EXGTYPE"
declare -x EXGHOST="${INPUT_EXGHOST:?"ERROR: The exchange host must be specified."}" # Catch for required varible
declare -x EXGURL="${EXGHOST/$EXGHOST/http\:\/\/$EXGHOST\/exchange}" # Changes the mail host into a http URL
declare -x EXGSURL="${EXGHOST/$EXGHOST/https\:\/\/$EXGHOST\/exchange}" # Changes the mail host into a https URL
declare -x EXGNAME="${INPUT_EXGNAME:=$INPUT_EXGHOST}" # If no name specified defaults to hostname of server.
declare -x EXGSSL="${INPUT_EXGSSL:="false"}"
declare -x EXGPUBFLDR="$INPUT_EXGPUBFLDR"
declare -x EXGURL="$INPUT_EXGURL"
fi
# -- SMTP Servers
if [ "$CONFIG_SMTP" = "YES" ] ; then
declare -x SMTPHOST="${INPUT_SMTPHOST:?"ERROR:The smtpoing server address must be specified."}" # Catch for required varible
declare -x SMTPAUTH="${INPUT_SMTPAUTH:=none}" # Defalts to none unless specified by the user.
declare -x SMTPNAME="${INPUT_SMTPNAME:="INPUT_SMTPHOST"}" # If no name specified defaults to hostname of server.
declare -x SMTPSSL="${INPUT_SMTPSSL:="false"}" # Defalts to false unless specified by the user.
declare -x SMTPPORT="${INPUT_SMTPPORT:="25"}" # Defaults to 25 unless specified by the user.
declare -x STMPUSEAUTH="${INPUT_SMTPUSEA:=YES}" # Defalts to YES unless specified by the user.
fi
##########################################################
# SANITY CHECKS #
##########################################################
# -- Required Commands installed check for every piece of software needed
CHECK_CMDS(){
for RQCMD in "$REQCMDS" ; do
if [ ! -x "$RQCMD" ] ; then
DIE "ERROR:$SCRIPT: the command $RQCMD is not available Ñ aborting" 192 >&2
fi
done
} # END CHECK_CMDS
CHECK_OS() {
case $OSVER in
10.0* | 10.1* | 10.2* | 10.3*) DIE "$FUNCNAME: Unsupported OS version: $OSVER." 192 ;;
10.4*) return 0 ;;
10.5*) DIE "ERROR:$FUNCNAME:$LINENO Unsupported OS version : $OSVER is too new." 192;;
*) DIE "ERROR:$FUNCNAME:$LINENO Unsupported OS version : $OSVER unknown version." 192;;
esac
} # END CHECK_OS
########################################################
# MAIN FUNCTIONS #
########################################################
RUN(){
CHECK_CMDS # Check for Require Commands
[ $CONFIG_MAIL != "YES" ] INJECT mail || DIE "ERROR: injecting incoming server config." 192
[ $CONFIG_SMTP != "YES" ] INJECT smtp || DIE "ERROR: injecting smtpoing server config." 192
[ $CONFIG_LDAP != "YES" ] INJECT ldap || DIE "ERROR: injecting LDAP config." 192
[ $CONFIG_EXG != "YES" ] INJECT exg || DIE "ERROR: Unkown error injecting exchange config." 192
} # END RUN
# Use Regex and postional parameters to verfiy input give to INPUT_* varibles
CHECK_USER_INPUT() {
}
# MAIN Inject Function for running respective injections.
INJECT(){
# Set the plist identifier
case "$1" in
mail) declare PLISTID="com.apple.mail" PREFKEY="MailAccounts" CHKHOST="$MAILHOST" MAILUUID="$($uuidgen)";;
exg) declare PLISTID="com.apple.mail" PREFKEY="MailAccounts" CHKHOST="$EXGHOST" EXGUUID="$($uuidgen)";;
ldap) declare PLISTID="com.apple.AddressBook" PREFKEY="AB3LDAPServers" CHKHOST="$LDAPHOST" LDAPUUID="$($uuidgen)";;
smtp) declare PLISTID="com.apple.mail" PREFKEY="DeliveryAccounts" CHKHOST="$SMTPHOST" SMTPUUID="$($uuidgen)";;
esac
# Start the recursion through the home directories starting with the console user first.
for CURRENTHOMEDIR in "$CONSOLEHOME" "${HOMEPATH}/*"; do
# For all users who's home directories that are in the HOMEPATH do the following:
# Test first for File Vault images and short circuit as some installers incorrectly create a ~/Library folder in this place holder directory when the users not logged in.
# Test to make sure the Directory ~/Library/Preferences/ exists ,Pretty much here for "/Users/Shared" "/Users/Deleted Users".
if [ -d "${CURRENTHOMEDIR}/Library/Preferences" ] ; then # Catch for "Deleted Users" and File Vault
# temp varibles for this recursion.
declare SERVICENAME="$1"
declare CNME=$($ls -ld "${CURRENTHOMEDIR}/Library" | $awk '{print $3}') # Pull the username from the ~/Library's owner.
declare PLIST="${CURRENTHOMEDIR}/Library/Preferences/$PLISTID.plist"
declare PLISTBACKUP="${PLIST}.bkp" # This is the file that you need to restore if the sky falls out from under us and the script does do it.
declare ISCONFIGTHERE=$($defaults read "${PLIST%.plist}" "$PREFKEY" | $grep $CHKHOST) || DIE "There was an error reading file: ${PLIST%.plist}"
# Check to see an the address-book plist exists for the script's current user on the system
# Check for plist and then move on or fail to else
if [ -f "$PLIST" ] && [ -z "$ISCONFIGTHERE" ] ; then # Check to see an LDAP Entry already exists for ldap.company.com
[ -f "${CURRENTHOMEDIR}/$CNME.sparseimage" ] || break
$cp -p "$PLIST" "$PLISTBACKUP" || DIE "There was an error copying the file $PLIST to $PLISTBACKUP." 192 # Back up the old preferences up before we change anything( copies and preserves permissions and adds a .bkp extension
INJECT_LDAP_ADD "$PLIST" $CNME
CHECK_PLIST "$PLIST" "$PLISTBACKUP" "$CURRENTHOMEDIR" "$PLISTID" || break # Check the plist for errors.
elif [ ! -f "$PLIST" ] ; then
INJECT_LDAP_CLEAN "${CURRENTHOMEDIR}"
# Check .plist for syntax errors,seems like it almost always exit with 0 , but cant hurt.
CHECK_PLIST "$PLIST" "$PLISTBACKUP" "$CURRENTHOMEDIR" "$PLISTID" || break # Check the plist for errors.
# Status info for the Installer Log
printf "%s\n" "The $SERVICENAME entry for $CHKHOST seems to already exist for $CNME please manually delete if you want it to be added by this installer"
fi
fi
done
# all is well even if we skipped the pref's because ldap.company.com was already there,mainly so you can run the script multiple times.
return 0
} # END INJECT
# Console function
CHECK_CONSOLE(){
declare -x CONSOLEUSER=$($who | $grep console | $awk '{print $1}')
}
# -- Kill processes like Mail and Address Book if there is a console user logged in.
QUIT_APPS(){
if [ -n $($who | $grep console | $awk '{print $1}') ] ; then
for APPS in "Mail.app" "Address Book.app"; do # This dont work yet
osascript <<EOF
try
tell application "System Events"
set IsMailRunning to count (every process whose name is "Mail.app")
if IsMailRunning is not equal to 0 then
tell application "Mail.app"
quit
end tell
end if
end tell
end try
EOF
done
fi
} # END CHECK_CONSOLE
# Check Active Directory users
CHECK_DIR_USER(){
declare CNME="$1"
declare ADCOMPASS="$defaults read /Library/Preferences/DirectoryService/ActiveDirectory \"AD Computer Password\" | $openssl enc -base64 -d"
declare ADCOMPNAME="$defaults read /Library/Preferences/DirectoryService/ActiveDirectory \"AD Computer Password\""
declare ADCOMPOU="$defaults read /Library/Preferences/DirectoryService/ActiveDirectory \"AD Computer Password\""
$ldapsearch -h $ADLDAPHOST -x -D "cn=${ADCOMPNAME},$ADCOMPOU" -w "$ADCOMPASS" -b "$ADLDAPBASE" "cn=$CNME"
unset ADCOMPASS
$dscl "$DIRNODE" -search / RecordName "$CNME"
} # END CHECK_ADUSER
INJECT_LDAP_ADD() {
declare CURRENTHOMEDIR="$1"
declare CNME="$2"
$defaults write "${CURRENTHOMEDIR}/Library/Preferences/com.apple.AddressBook" "AB3LDAPServers" -array-add "
<dict>
<key>ServerInfo</key>
<dict>
<key>AuthenticationType</key>
<false/>
<key>Base</key>
<string>$LDAPBASE</string>
<key>Enabled</key>
<true/>
<key>HostName</key>
<string>$LDAPHOST</string>
<key>Port</key>
<integer>$LDAPPORT</integer>
<key>SSL</key>
<${LDAPSSL:-"false"}/>
<key>Scope</key>
<integer>2</integer>
<key>Title</key>
<string>$LDAPHOST</string>
<key>UID</key>
<string>$LDAPUUID</string>
<key>Username</key>
<string>$LDAPUSER</string>
</dict>
<key>ServerType</key>
<integer>0</integer>
</dict>
"
} # END INJECT_LDAP_ADD
# Generate a new preference file as it doesnt exist, with the default values added and an entry for out ldap server.
INJECT_LDAP_CLEAN() {
declare CURRENTHOMEDIR="$1"
declare CNME="$2"
printf "%s\n" "Writing new preference file with $LDAPHOST entry for $CNME in ${CURRENTHOMEDIR}/Library/Preferences/com.apple.AddressBook"
$defaults write "${CURRENTHOMEDIR}/Library/Preferences/com.apple.AddressBook" "
<dict>
<key>AB21vCardEncoding</key>
<string>MACINTOSH</string>
<key>AB3LDAPServers</key>
<array>
<dict>
<key>ServerInfo</key>
<dict>
<key>AuthenticationType</key>
<false/>
<key>Base</key>
<string>$LDAPBASE</string>
<key>Enabled</key>
<true/>
<key>HostName</key>
<string>$LDAPHOST</string>
<key>Port</key>
<integer>$LDAPPORT</integer>
<key>SSL</key>
<${LDAPSSL:="false"}/>
<key>Scope</key>
<integer>$LDAPSCOPE</integer>
<key>Title</key>
<string>$LDAPHOST</string>
<key>UID</key>
<string>$LDAPUUID</string>
<key>Username</key>
<string>${LDAPUSER:=}</string>
</dict>
<key>ServerType</key>
<integer>0</integer>
</dict>
</array>
<key>ABAIMInstantVisible</key>
<true/>
<key>ABAddressesVisible</key>
<true/>
<key>ABCardPaneFrame</key>
<string>{{260, 0}, {300, 207}}</string>
<key>ABDefaultAddressCountryCode</key>
<string>us</string>
<key>ABDefaultLayout</key>
<integer>0</integer>
<key>ABDefaultSelectedMember</key>
<string>$LDAPUUID:ABPerson</string>
<key>ABEmailsVisible</key>
<true/>
<key>ABGroupsPaneFrame</key>
<string>{{0, 0}, {120, 207}}</string>
<key>ABHomePageVisible</key>
<true/>
<key>ABImportTipCards</key>
<true/>
<key>ABIndexVersionKey</key>
<integer>2</integer>
<key>ABMembersPaneFrame</key>
<string>{{125, 0}, {130, 207}}</string>
<key>ABMetaDataChangeCount</key>
<integer>180</integer>
<key>ABNameDisplay</key>
<integer>0</integer>
<key>ABNameSorting</key>
<integer>1</integer>
<key>ABPeopleColumnsWidth</key>
<real>113</real>
<key>ABPhoneFormat-Edited</key>
<false/>
<key>ABPhoneFormat-Enabled</key>
<true/>
<key>ABPhoneFormat-PhoneFormatter</key>
<array>
<string>+1-###-###-####</string>
<string>1-###-###-####</string>
<string>###-###-####</string>
<string>###-####</string>
</array>
<key>ABPhonesVisible</key>
<true/>
<key>ABRelatedRecordsVisible</key>
<true/>
<key>ABSKCompactionHint</key>
<integer>3</integer>
<key>ABSeparateWindowsFrames</key>
<array/>
<key>ABSeparateWindowsHiddenUIDs</key>
<array/>
<key>ABSeparateWindowsUIDs</key>
<array/>
<key>ABTextSizeFixed</key>
<true/>
<key>NSPreferencesContentSize</key>
<string>{461, 414}</string>
<key>NSPreferencesSelectedIndex</key>
<integer>0</integer>
<key>NSWindow Frame Preferences</key>
<string>26 91 593 390 0 0 1024 746 </string>
</dict>"
return 0
} # END INJECT_LDAP_CLEAN
CHECK_PLIST(){
declare PLIST="$1"
declare PLISTBACKUP="$2"
declare CURRENTHOMEDIR="$3"
declare PLISTID="$4"
declare CGID=$($ls -lnd "${CURRENTHOMEDIR}/Library" | $awk '{print $4}')
declare CUID=$($ls -lnd "${CURRENTHOMEDIR}/Library" | $awk '{print $3}')
$chown "$CUID":"$CGID" "$PLIST" # As this script is running as root we need to change the POSIX permissions,I use numerics for the parent pref's folder.
if [ $($plutil -lint "$PLIST") ] ; then # Check .plist for syntax errors,seems like it almost always exits with 0 , but cant hurt.
return 0
else
printf "%s\n" "WARNING: There was a problem editing plist: "${CURRENTHOMEDIR}"/Library/Preferences/${PLISTID}.plist"
printf "%s\n" "Reverting to copy: $PLISTBACKUP and continuing on."
$mv -f "$PLISTBACKUP" "$PLIST" # Replace old plist with orginal.
return 192
fi
} # END CHECK_PLIST
# Inject incoming.
INJECT_INCOMING() {
# Dump the raw XML "dictionary" into a new array called
# This will be additive and should not destroy any data.
# and the forums said you cant add a dictionary to an array with defaults
declare CURRENTHOMEDIR="$1"
declare CNME="$2"
$defaults write "${CURRENTHOMEDIR}/Library/Preferences/com.apple.mail" "MailAccounts" -array-add "
<dict>
<key>AccountName</key>
<string>$MAILNAME</string>
<key>AccountPath</key>
<string>~/Library/Mail/IMAP-$CNME@$MAILHOST</string>
<key>AccountType</key>
<string>$MAILTYPE</string>
<key>AuthenticationScheme</key>
<string>$MAILAUTH</string>
<key>DateOfLastSync</key>
<date>$UTCDATE</date>
<key>DaysBetweenSyncs</key>
<integer>7</integer>
<key>DraftsMailboxName</key>
<string>Drafts</string>
<key>EmailAddresses</key>
<array>
<string>$CNME@$MAILDOMAIN</string>
</array>
<key>FullUserName</key>
<string>$CNME</string>
<key>Hostname</key>
<string>$MAILHOST</string>
<key>ISPAccountID</key>
<string>$UUIDGEN</string>
<key>SMTPIdentifier</key>
<string>$MAILHOST:$CNME</string>
<key>SentMessagesMailboxName</key>
<string>Sent Messages</string>
<key>StoreDraftsOnServer</key>
<string>YES</string>
<key>StoreSentMessagesOnServer</key>
<string>YES</string>
<key>TrashMailboxName</key>
<string>Deleted Messages</string>
<key>Username</key>
<string>$CNME</string>
<key>uniqueId</key>
<string>$MAILUUID</string>
</dict>"
mkdir -p $HOME/Library/Mail/IMAP-$CNME\@$MAILHOST/INBOX.imapmbox/ # Not sure I need this
$defaults write $CURRENTHOME/Library/Preferences/com.apple.mail "ReleaseNotesVersion" -int "3" # Or this
} # END INJECT_INCOMING
# Inject the SMTP server configuration.
INJECT_OUTGOING() {
declare CURRENTHOMEDIR="$1"
declare CNME="$2"
$defaults write ${CURRENTHOME}/Library/Preferences/com.apple.mail "DeliveryAccounts" -array-add "
<dict>
<key>AccountType</key>
<string>SMTPAccount</string>
<key>Hostname</key>
<string>$SMTPHOST</string>
<key>PortNumber</key>
<string>$SMTPPORT</string>
<key>SSLEnabled</key>
<string>$SMTPSSL</string>
<key>ShouldUseAuthentication</key>
<string>${SMTPUSEA:-YES}</string>
<key>Username</key>
<string>$CNME</string>
<key>uniqueId</key>
<string>$SMTPUUID</string>
</dict>"
return 0
} # END INJECT_OUTGOING
# Install a Mail "Template" or what Apple calls a Mail Bundle
INSTALL_TEMPLATE() {
$defaults write "${TEMPLATEPATH}" -dict "
<key>AccountIconName</key>
<string>$MAILNAME</string>
<key>Accounts</key>
<array>
<dict>
<key>AccountID</key>
<string>$MAILUUID</string>
<key>AccountName</key>
<string>$MAILNAME</string>
<key>AuthenticationScheme</key>
<array>
<string>$MAILAUTH</string>
</array>
<key>AuthenticationSchemeIsEditable</key>
<false/>
<key>DeliveryAccounts</key>
<array>
<string>$($uuidgen)</string>
</array>
<key>EmailAddressDomain</key>
<string>@$MAILNAME</string>
<key>PortNumber</key>
<integer>$MAILPORT</integer>
<key>Protocol</key>
<string>$MAILTYPE</string>
<key>SSLEnabled</key>
<${MAILSSL:-false}/>
<key>SSLEnabledIsEditable</key>
<false/>
<key>ServerName</key>
<array>
<string>$MAILHOST</string>
</array>
<key>ServerNameIsEditable</key>
<false/>
<key>UserNameMatchesEmailAddress</key>
<true/>
</dict>
<dict>
<key>AccountID</key>
<string>$SMTPUUID</string>
<key>AccountName</key>
<string>$SMTPNAME</string>
<key>AuthenticationScheme</key>
<array>
<string>$SMTPAUTH</string>
</array>
<key>AuthenticationSchemeIsEditable</key>
<false/>
<key>PortNumber</key>
<integer>$SMTPPORT</integer>
<key>PortNumberIsEditable</key>
<false/>
<key>Protocol</key>
<string>SMTP</string>
<key>SSLEnabled</key>
<${SMTPSSL:-false}/>
<key>SSLEnabledIsEditable</key>
<false/>
<key>ServerName</key>
<string>$SMTPNAME</string>
<key>ServerNameIsEditable</key>
<false/>
</dict>
</array>
<key>Identifier</key>
<string>$MAILIDFR</string>
<key>Version</key>
<integer>1</integer>"
return 0
} # END INSTALL_TEMPLATE
# Install LaunchD item for auto run of application?
INJECT_LANUCHD() {
declare LAUNCHJOB="$1"
declare WATCHFOLDER="$2"
$defaults write ${CURRENTHOMEDIR}/Library/LaunchDeamons/$MAILIDFR.notify "
<dict>
<key>Label</key>
<string>$MAILIDFR.notify</string>
<key>ProgramArguments</key>
<array>
<string>$LAUNCHJOB</string>
</array>
<key>QueueDirectories</key>
<array>
<string>$WATCHFOLDER</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>WatchPaths</key>
<array>
<string>${CURRENTHOMEDIR}/Library/Mail</string>
</array>
</dict>"
return 0
} # END INJECT_LANUCHD
EXPORT_CONFIG(){
printf "%s\n" >"$CONFIGFILE"
return 0 # Return all is well.
}
# Create a package installer (.pkg) capable of pushing this mail configuration through Apple Remote Desktop.
CREATE_PKG() {
# "Sub" Functions for creating Package info.plist.
CREATE_PKG_INFO(){
declare SESSIONTMP="$1"
defaults write "${SESSIONTMP}/Info" "<dict>
<key>CFBundleGetInfoString</key>
<string>0.1, ${MAILDOMAIN:="Mail Installer"}</string>
<key>CFBundleIdentifier</key>
<string>${MAILIDFR}.mailconfig</string>
<key>CFBundleShortVersionString</key>
<string>0.1</string>
<key>IFMajorVersion</key>
<integer>0</integer>
<key>IFMinorVersion</key>
<integer>1</integer>
<key>IFPkgFlagAllowBackRev</key>
<false/>
<key>IFPkgFlagAuthorizationAction</key>
<string>AdminAuthorization</string>
<key>IFPkgFlagBackgroundAlignment</key>
<string>topleft</string>
<key>IFPkgFlagBackgroundScaling</key>
<string>none</string>
<key>IFPkgFlagDefaultLocation</key>
<string>/</string>
<key>IFPkgFlagFollowLinks</key>
<true/>
<key>IFPkgFlagInstallFat</key>
<false/>
<key>IFPkgFlagInstalledSize</key>
<integer>900</integer>
<key>IFPkgFlagIsRequired</key>
<false/>
<key>IFPkgFlagOverwritePermissions</key>
<false/>
<key>IFPkgFlagRelocatable</key>
<false/>
<key>IFPkgFlagRestartAction</key>
<string>NoRestart</string>
<key>IFPkgFlagRootVolumeOnly</key>
<false/>
<key>IFPkgFlagUpdateInstalledLanguages</key>
<false/>
<key>IFPkgFormatVersion</key>
<real>0.10000000149011612</real>
</dict>"
return 0
} # END CREATE_PKG_INFO
# Sub Function for creating package description.
CREATE_PKG_DISC(){
declare SESSIONTMP="$1"
defaults write "${SESSIONTMP}/Description" "
<dict>
<key>IFPkgDescriptionDescription</key>
<string>Title
Line1
Line2
Line3</string>
<key>IFPkgDescriptionTitle</key>
<string>Mail Configuration Installer</string>
</dict>"
return 0
} # END CREATE_PKG_DISC
# -- Package Installer and Mail Template.
declare PKGLOC="${INPUT_PKGLOC:=/Users/Shared/mailconfig.pkg}"
# Check to see if package maker is executable and where we think it is.
if [ ! -x "$packagemaker" ] ; then
DIE "Package Maker does not seem to be installed ; You must have to the Developer tools installed to use this feature. file: ${packagemaker}"
fi
# CREATE_PKG_DISC session variables.
declare SESSIONTMP="/private/tmp/${0##*/}_${$}_${EUID}" # Create temp directory for the session, ala /private/tmp/nameofscript_PID_EUID/
declare PKGSCPTS="${SESSIONTMP:="/tmp"}/rsrcfiles" # Package resources, in this case the scripts and config files.
declare FAUXROOT="${SESSIONTMP:="/tmp"}/fauxroot" # The faux or "dstroot"
declare PKGINFO="${SESSIONTMP:="/tmp"}/Info.plist" # The packages info plist
declare PKGDISC="${SESSIONTMP:="/tmp"}/Description.plist" # The packages description plist.
printf "s\n" "Creating temp directory in $SESSTMP for package maker files."
for TEMPFOLDERS in "$SESSIONTMP" "$PKGSCPTS" "$FAUXROOT"; do
printf "%s\n" "Attempting to create temp directory ${TEMPFOLDERS}"
$mkdir "${TEMPFOLDERS}" || DIE "ERROR: The creating directory: $TEMPFOLDERS ." 192
done
printf "%s\n" "Copying ${SCRIPTPATH} ${PKGSCPTS}/postflight."
$cp "${SCRIPTPATH}" "${PKGSCPTS}/postflight" # Move this script in to the postflight.
$cp "$CONFIGFILE" "$PKGSCPTS/" || DIE "ERROR: The config file: $CONFIGFILE was not found" 192 # Copy the current settings to the package scripts directory.
CREATE_PKG_INFO "$SESSIONTMP" # Create Info file in the session's temp directory.
CREATE_PKG_DISC "$SESSIONTMP" # Create Discription file in the session's temp directory.
$mkdir -p "${FAUXROOT}Library/Mail/AccountTypes/" && INSTALL_TEMPLATE "$FAUXROOT" # Create mail template or "bundle" file to be installed in root directory.
$packagemaker -build -p "$PKGLOC" -ds -f "$FAUXROOT" -r "$PKGSCPTS" -b "/private/tmp/" -i "$PKGINFO" -d "$PKGDISC" # use package maker to create package.
return 0
} # END CREATE_PKG
##################################################
## CLEANUP ##
##################################################
trap CLEAN_UP SIGHUP SIGINT SIGTERM
unset -f CLEAN_UP
@acidprime
Copy link
Author

Automatic Mail Configuration in Mail.app and Entourage
Introduction (Feel free to skip to setup)
Email account settings are one of those things that most end users have to deal with at some point in their career,some times its just to call IT to help the user setup a new account,or more often to have IT setup a new account for a new employee. Sometime its trouble shooting a connection over the phone due to a hotel SMTP restriction or just incorrect “external” settings leading to a “it worked at the office” problem. Either way while its a relatively small amount of information which in the case of email software (clients) you only have to enter in once, To the uninitiated its a smorgasbord board of acronyms and complex names they don’t care (nor should they need) to remember.
I hope to show you In this article that by leveraging built-in technologies like Apple Script,Installation packages and potentially Launchd or Login items you can allow your end users to enter/verify just their Account ID,Full Name and Reply to Address to complete setup for a new account. In fact using some semi-fancy piece's of code you can have defaults entered if for them,so they just have to change what they like for instance “Zach Smith” to “Zack Smith”, Meaning now your users can setup new email accounts by just pressing return and following the prompts. Apple’s Mail.app program provides help with this by using templates that you can create and that are tightly integrated into Mail as of v10.4 .In addition with supplied Apple Script’s that can be used as the basis for your own scripts you can make a automated application for setting up a new account. In writing this article I have also included some fairly complete scripts which you can use to start with just by changing the variables to suit your configuration.
Microsoft Entourage is a slightly more manual configuration as it does not support any documented account templates, currently like Mail.app it also supports a rich Apple Script layer which can allow you create scripts that with a careful placement can provide some basic “template” functionality. This article is divided in sections pertaining to the respective email software you are using and the intended deployment methodology .I have sectioned these off by Single user(s),All users on a local system and All users on s network system like (Active | Open) Directory. One last note,the following PDF is link-alicious many items have file system links that will open up folders,applications and even scripts in your console,I have tried to make these links as non-destructive as possible, however I would recommend verifying your path names and intended results before pressing the “run” button. See below for more legal disclaimers,bu enough non-technical info on to the good stuff.
Configuring Mail.app
Setup of initial files,
Mail.app provides account template know as mail bundle’s to allow easy templates to be created. If you own a .Mac email address and have configured Mail.app without entering in “mail.mac.com” chances are you did so by Using the default mac.com template. Meaning you only had to enter in your Account ID , Full Name and Reply Address.
--Screen Shot Mail.app setup screen.
These templates live in /Library/Mail/AccountTypes/ by default. They are folders named using the reverse java name naming covetions found in most preferences in the syste,so com.mac.mailaccounts is mac.com’s template.The first step in creating a template is to create a folder using this convention i.e. “org.wallcity.mailaccounts” .We will talk about about where this will live and the permissions required in the next two sections for right now you can throw it anywhere,like your desktop.
If you take a look at the structure of /Library/Mail/AccountTypes/com.mac.mailaccounts/ you can see that inside the folder we have some localized folders such and English.lproj and French.lproj which mainly relate to language specific setting primarily relating to the name presented in fig A. The real meat of this “bundle” however is the MailAccounts.plist a XML based preference containing all of the settings you would like to configure the account with and wether you would like optionally just supply defaults for this config allowing the user to change some settings like weather SSL is used. in fact other then the small tiff file the MailAccounts.plist is the only thing that is required to make a template. You can edit the plist using the Property List Editor installed as part of the Developer Tools in /Developer/Tools/Application/Utilities . Each field in the template has a specific type respective to the information it will contain. For instance a number such as the port your smtp server runs on is the type “integer” and can only contain whole numbers. While the human readable name for the account itself is a string or a type that can contain letters and numbers. You can create this keyname(type)=value from scratch for the settings out lined in Fig C but a less work intensive option is to make a copy of the Apple supplied and place in the folder created earlier. Using this method you can change the fields to match your values and add any missing values your self. This may also help you if you are new to the Property list editor.
--insert chart and note about special folders!
The only down side of using of using the .Mac template is as you can see above according to the chart it two unique identifiers know as a Generated UID or GUID,this 128 bit number is how the system tracks these accounts. One of these is used for the account as a whole and the other in the SMTP server.More importantly as you can see it is a specific format and duplicating it between accounts could lead to undesirable results so we will need to generate a new one. This can be done with the uuidgen tool.
/usr/bin/uuidgen
B279B3D6-E9CF-4506-808A-375662C89D7C
/usr/bin/uuidgen
50644558-D382-4499-B173-1DE9251A8F3C
Running the command twice will give us two new unique identifiers we can cut in paste in those two fields in any order we like. There is no problem generating this identifier on your production computer and deploying to your workstations,and having every account template has the same GUID, this kind of configuration will work fine which is evident as all “.Mac” templates share the GUID among all 10.4 Mac’s com.mac.mailaccounts bundle.The uuidgen command can be run as many times as you like,it will provide a unique value covered more in depth by reading its man page.
After you have generated a new GUID and modified your template to match your specific mail settings your basically ready to go.The last piece of good measure is the .tiff file mentioned earlier,this a a 128x128--fix pixel logo graphic displayed next to your “Templates Name”. You can use your favorite photo editor to resize you company logo to this size,however be aware to make things look nice you might want include a alpha layer like com.mac.tiff,or just cut and paste your graphic on top the applied tiff,or just rename the .Mac to your reverse java name .tiff
--little screen shot of tiff file
Now for testing purpose’s you can throw your file in /Library/Mail/AccountTypes/ and open up or re-open mail to see the account template show up either in the setup assistant if you have never configured mail or by retroactively accesing the assistant with the plus button in accounts.If everything worked and a template if all your deployment if going to contain you can move on the one of the respective sections below. Once you have verified it works yeah can move it back of AccountTypes and move on to one of the deployment sections, or read on for an introduction to increasing value with scripting.
--plus button with big cursor graphic -- wallcity logo
Setup script introduction
( you can script this and go right to a outline of the supplied example in section 7-A)
Now lets talk about a slightly different methodology which can be used in conjunction or independent of templates. In this method we will use a (Apple/Shell) Script which has the distinction of being interactive and allows you test the limited input your users are entering in. For instance,the template above does not really provide feedback if the user enters in their account ID in the wrong format or if they ignore the visual indicator and enters in their email address instead their Account IDs.Common errors may have to do with entering in the account-ID in the wrong case,what if the user has already has setup Mail.app and is now moving to entourage cant our script just grab that username? First a little background about our primary mechanism for configuring accounts: Apple Script. Apple Script is normally billed as a “English Like” language ,most of its syntax is based around the idea of a sentence,though as most developer discover as they delve into write anything beyond basic script that its nature of sounding like English can at times be counter productive. The normal example of this is the code compiling in such a way that the nun who taught me English would fail slap me hand for. That said getting around semantical and esoteric concerns applescript does something that no System admin can ignore,it can talk to programs like Mail and enter in information using code supplied by the original developer( known in the applescript lexicon as a Dictionary). This means we dont have to write raw preferences editor type scripts that could out of date as fast a parachute pants because of a version change or a feature being added thus changing the original format and or option in the pref. A quick look at the dictionary supplied by Mail show’s a an account object capable of handling values much like our mail bundle.
-- Mail.app AppleScript Dictionary
The idea of doing programing a setup template in Apple Script seem all the more feature rich when we discover that it is cable of running routines and doing basic text manipulation. More importantly for those of you who work in your shell as much as your cubicle, you will be happy to know two things: one is that using the Apple Script command “do shell script” you can run shell commands and two that you can trade the output and input of these commands back and forth is Applescript in variable's used in your Apple Script. While this does cause a little bit of double commented text thats harder to read it also acts as a supplemental layer for your script so you can perform things that neither shell programming or Apple Script can easily do alone. So a basic script for mail setup would contain a few things in practice:

  1. Dialogs that allow the user to enter information such as the Account ID,Full Name etc.
  2. Some basic checking of that information done by either Applescript or Some (other | better) tools like (e)grep sed, awk and perl in conjunction with Regular Expressions.
    Checking for the account ID’s structure by delimiter if any “.” “_”
    Checking for the correct case (normally lower for account IDs)
    Checking for the character limit in the account IDs (not as common)
    Finally checking for common mistakes like entering a email address
    or other variations like SAM conventions in Active Directory
  3. Configure (talk) to the respective application saving the “clean” setting for the new account in the appropriate fields
    Well normally its the top two items that take the longest,given basic error checking and syntax tools are written to expect values that are potentially random, for instance a typo or a user entering in a email address in the wrong field such as the Account ID.Item number 3 is that one is in actually almost completely done for you due to Apple’s own Apple Script staff. In the /Library/Scripts folder you will find items used by the Script Editors #Link# Script menu preference. Of particular interest are two items Named “Create New Mail Account.scp” and “Create New LDAP Server.scpt” these give the basic syntax for building your own script in Mail.app. Looking back to the dictionary listed above you can reverse engineer these scripts to make a more basic script cable of asking the user for some information and making a new account based around that information.
    I am intentionally simplifying the idea of doing this as I am providing some example scripts that are more tailored to the purpose of this article. I will tell you though that I did not start really using Apple Script Syntax until writing this article and even then I still have not saturated it capabilities. I had used of-course it as a problem solving tool with one liners and single purpose scripts for instance with ARD missing a change volume command like it predecessor (ANAT) I would use something like “osascript -e ‘set volume’ to send a UNIX->AppleScript Command or to solve actions that where tedious and easy to automate but like many IT folks using Apple script day to day eluded me mainly because of it english like nature seemed cumbersome in more complex scripts It was also too “simple” that I refused to research it, confident in my ability to speak my native tongue not able to spread my ideas around its syntax. So simple it seemed that it wasn’t until forced to use it for things like repeating subroutines that I finally cracked open my O’rielly book again instead of assuming that I knew how to use it inherently..
    So its more then possible given some (hopefully) good examples and a working knowledge of Mac OS X that you too can architect something that will work in for your particular environment,Apple Script can be bizarre but when you look at a script to enter in account information,mostly its a four sentence affair that grows only larger by you willingness of available time to build in error checks, which to be far don’t exsist
    (Section 7-A)
    -- Outline of Mail.app Example Script.
    While going through every line of my script is better suited by the semi logical variable names and comments “--”&“(*_)” found in the script its self. A basic match up its components or “_handlers” is presented below next to the three chunks introduced early on in the article
  4. Dialogs that allow the user to enter information such as the Account ID,Full Name etc.
  5. Some basic checking of that information done by either Applescript or Some (other | better) tools like (e)grep sed, awk and perl in conjunction with Regular Expressions.
    Checking for the account ID’s structure by delimiter if any “.” “_”
    Checking for the correct case (normally lower for account IDs)
    Checking for the character limit in the account IDs (not as common)
    Finally checking for common mistakes like entering a email address
    or other variations like SAM conventions in Active Directory
  6. Configure (talk) to the respective application saving the “clean” setting for the new account in the appropriate fields and completing the setup

A quick jaunt in to package installers.
--Screen shot galore.
Building packages is some thing many administrators eventually find to be a helpful
for pushing out files/folders to basically anywhere the user running the install can access.These packages can also be pushed out via the Apple Remote Desktop software allowing for unattended or even background installs.
Creating Package Install is surprisingly easy especially using the developer new tools.
Lets break it in to three to steps for simplicity:
Deciding where you want things installed and creating a structure to mirror that.
Coping your items to this structure and noting permissions and post actions.
Building and Deploying your package and filling the gaps with documentation

Testing is always an important thing in line with measure twice cut once.
Remember its not
--Mail icon -- Deploying our Templates and Script for Mail.app
Deploying for One User local User
The package method with Mail Bundles
Deciding where you want things installed and creating a structure to mirror that.
The Account Template
for just one user mail bundles can be installed in to
~/Library/Mail/Account Types/
# note that this folder is not there by default
as noted earlier install items in the home folder. typically need to be installed into an intermediary location like /tmp/myinstaller and moved using variables in the post action scripts of the installer.
Coping your items to this structure and noting permissions and post actions.
So in my fauxroot I create /tmp/Account Types/ so my script can move it to
~/Library/Mail/Account Types/ which will make it accecible to only the
currently logged in user and will require no authentication to install
mv /tmp/Account Types/ $USER/Library/Mail/Account Types/
Building and Deploying your package and filling the gaps with documentation
documentation ,special folders with mail.
to reboot or not reboot?
disk image internet enable

    The Script File ( Complied Application )

Because your script must be run not necessarily be installed you can place it or install it anywhere it can run,even a thumb drive! Also the idea of the “setup” script is that is it will probably only ever be run once so having it in a more central location like posted on a webserver,may not be a bad thing for versioning copies in case you make updates.
To post your script on a server you will first want to save it as a application,so all your users will have to do to run it is double click on its icon,this can be done after you are done making your changes in the script editor by choosing
Save>As Application and un-checking “stay up” for good measure.
-- save as screen shot in script editor
We then can create a folder that will be the basis of a our Disk image are about to create,we can then move/copy our saved application into this folder
--Folder created?
Using the Disk Utility we can create a “New> Disk Image from Folder”
selecting the root of the folder we create above and saving on our desktop.
note an odd behaviour in some versions of disk utility presents the folder
you are creating the dmg from as also the save location,just pick Desktop.
Last but not least lets make this dmg internet enabled just like we did our template above,so it will shed its skin upon download only leaving the application our users to click on and run.
Deploying for All Local Users
The Search Path: Mail bundles for all!
As I am sure you have already guessed in testing your new bundle if you place it in /Library/Mail/Account Types/ all users on the local the system can see it.
-- two users side by side screen shot.
As this folder is a static value and already exists on a standard v10.4 system to deploying a bundle for all users you simply need create it in your fauxroot with place holders for /Library/Mail/Account Types/ and make sure the installer has been set to require administration privileges as /Library is writable only by admins
No post action is required as you don’t need to move anything around, For good measure you might want to however to think about removing or overwriting the default “.Mac” MailAccounts.plist so your list will show your companies bund first in the pop up menu,this can be done pretty easily by modifing the Blank field
The User Template: Skeletons in Mac OS X’s closet.
Have you ever wondered where the default folder structure comes from like Movies,Picture etc.Well when a new user is create the folders/files are copied in the case of english from /System/Library/User Template/English.lproj.
The folders (and permissions) become the basis of all newly created users,so if you would like everyone to have a folder called “Work” in all new users home directorys you can pretty easily do so by modified the contents of this folder.
Doing so requires Root access and can be done using the graphical interface if the root account is “enabled” by virtue of its password being set or via the command line privilege elevator sudo so I can copy in my “Work” folder by typing in sudo cp /path/to/Work /System/Library/User Template/English.lproj/
You may want to check the resulting permissions ( and ownership ) for security to check that the resulting items can be read and written to be only the user, and not modified further by other malicious local user,though its not likely the could.
Permissions: (“700” synonymous with “u=rwx,g=r,o=r”)
sudo chmod -R 700 /System/Library/User Template/English.lproj/Work
Ownership: ( “0:0” synonymous with “root:wheel”)
sudo chown -R 0:0 /System/Library/User Template/English.lproj/Work

LDAP and the User Template(Network accounts can probably skip this)
I could tell you that you put your account Mail bundles in the home folders of all      newly created users but a more sane way of doing this with /Library has been        covered. Remember however that these bundles do not setup Address Book      though so any user who does not run our script and uses this bundle to setup        their email would be missing the auto completion from our ldap server. One all or       nothing approach to this is to have the address book already configured for all     newly created users,this means even if they never use the template their address        books automatically have ldap.company.com listed.
This is as easy and opening up Address Book on a fresh account, changing the        preferences by setting the ldap server, Quitting Address book grabbing the      com.apple.address book preference that was just created in fresh accounts       ~/Library/Preferences and moving/copying that to the User template using 
sudo cp ~/Library/Preferences/com.apple.addressbook.plist
    /System/Library/User\ Template/English.lproj/Library/Preferences/
    # Note a space between .../com.apple.addressbook.plist  /System/...
Scripts and the User Template
As mentioned our scripts can live on a webserver somewhere if you like but you      may in an all users setup want to have a copy of the script easily accessible,      especially if you use a more fancy option like Login items covered below.
Good places for this could be /Applications/ or /Library/Whatever . Add either of       these place holders to your fauxroot and instruct your users to look there to find      your Script during Setup.You could also put it in the user template for later instal        lation in ~/Library/Application Support but this again is not really needed because     you can create /Library/Application Support/Wallcity/ instead.
Musical Chairs our Script and all new Users.
Now that we have the script is a place where all users can access it (and run it        depending on the read permissions we gave in the fauxroot ) Using the user      template we can create a new dock preference,com.apple.dock.plist move a        reference to our script living in /Library/Application Support/Wallcity/ to it,even put     it right next to the Mail.app icon. What if though it was the Mail.app icon? and        Mail.app was not ever listed,meaning the users could only click our script?
Well that is more then possible to if we cut & paste the Mail.app icon and then     add that item to the dock and that dock preference to the user template.            What about after the first setup?We don’t want the setup script to run every time     we and certainly don’t want the user to have to go and re-add Mail.app to their       dock.Well we can solve this by adding a fix up routine to our script to change the      dock preference path from 
/Library/Application Support/Wallcity/MyScript.app to /Applications/Mail.app on         successful completion and Restart the dock to reread the preference.
--example code with note that its not in the example code due to the setup.

Deploying for All Network and Existing Users and (Apple Remote Desktop Clients)
Account Templates and the /Network/Library/ folder.
For those you who have Open Directory or Active Directory(w/Extended Schema) servers you have another way of providing these bundles to your users.
By virtue of Network Mounts sometimes referred to as Auto Mounts, you can mount a folder on the server under the /Network/ folder this “Library” folder is part of the standard search path for resources.So Mail will look in /Network/Library/ Mail/Account Types even though its a folder “mounted” on a remote server via AFP or NFS.This means anyone bound to your Open/Active Directory or Magic Triangle system can access these templates automatically.
The details of promoting an Open Directory Master or extending a Active direc- tory server to support mount records are beyond the scope of this article ,realize though that if you have a system like this in place all you need to do is create the local “Library” to be shared out in /Network/Library, perhaps in /Shared items/ Library or on your data volume. Make it a share point using the share this item check box in Workgroup Manager and Clicking over to the Network Mount Tab.
--tri screen shot for Sharing button,Share this item, Network mount on bottom.
If you are sharing this item via AFP guest access must be on and your bound clients wont see it until they have been at least rebooted( other methods too).
The MCX Login and Launch item method
As mentioned you can keep your script tucked away in any number of Directory’s /Library/Applications Support/ /Library/Management/ /Library/Scripts
once you decided on a location you can place musical chairs with Mail.app or create a once time Login Items Prefences and a fix up in your script.
Post action scripts and Existing Users and Apple Remote Desktop
So far we have looked at Setting up a Mail.app and Address Book individually using Apple Script affecting just the console user.We have discussed creating Mail account Bundles and modifying the default address book preference so newly created users will have a “Template” to setup IMAP and have LDAP al ready configured. What about users who where already there before the install? What about if we want to distribute the account information to workstations with no (active) console user logged in?A senerio of no console user is pretty com mon when installing a package over ARD,postflight scripts that contain variables like ~ or $HOME will not work appropriately with no console running a install in fact will probably expand to /var/root on most occasions as the root user is the effective user for ARD package installs.
Now I dont want to scare you off,but our solution is our last scripting lan guage, Which is every scripting and programming language under then sun,perl python, ruby, objective c and many more.These languages have the benefit that un-like Apple Script can easily run in the background with out a console user and have access to thousands of applications and APIs to do everything your ever wanted.That said I am not going to use ANY of them in my example.I choose bash due to the fact that some of these are older scripts I have written and that for this purpose I didn’t beyond the built-in shell constructs.
In my example below you can see a starter script that uses the defaults com mand to recursively go through the /Users/ folder and Add in a non- destructive fashion account settings for Mail.app and Address Book.
Editing preferences directly has two main concerns,
One is corruption of the file/structure/version of the plist minimized by checking the plist after editing and backing it up before any modification is made.
The other is compatibility, What is Mail.app changes its preferences structure after an update?
This is minimized by Apple Them selves, if Mail.app cant read its preference from build to build preference problems would crop on other places like Migrating from an old machine 10.4.1 to a new machine 10.4.7.While preference change between version 10.4 and 10.3 10.4.x-10.4.9 will most likely have the same preference options and format for compatibility.If your worried about the 10.5 transition and rewriting your scripts,realize that much of this auto configuration is done for you in 10.5 and so wont even be needed.
--out line of shell script.
All of the Above
Entourage
Deploying for One User local User
Deploying for All Local Users
Deploying for All Network Users.

This setup documentation is provided as-is and I am not liable for any lost data or unforeseen complication arising from using the supplied instructions or scripts. That said if you find the scripts really useful and feel like donating to my *Computer book fund,also known as the “Mac OS X Fundamentals is 70$ fund :)” you can find my pay pal here.

  • According to Quicken in 2005 I spent $978.50 on my O’rielly wild life sanctuary.

@acidprime
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment